I'm using Jax RS 2.0 ContainerRequestFilter
I want to intercept entity body (if any) and convert to original type.
I can get original class type by using inkected ResourceInfo
resinfo.getResourceMethod().getParameters()
However I have no idea on how to get parameter value...
The only closes object is an EntityStream(), available from:
containerRequestContext.getEntityStream()
I guess I should use the above object, but how I can rebuild original object from entityStream ?
I found a way, it is enought to implement ReaderInterceptor interface:
#Override
public Object aroundReadFrom(ReaderInterceptorContext readerInterceptorContext) throws IOException, WebApplicationException {
final Object proceed = readerInterceptorContext.proceed();
return proceed;
}
Related
I am using jaxrs 2.0 & am trying to populate an object in the ContainerRequestContext & retrive it in the business logic.
I am populating the object in the ContainerRequestContext like :
#Override
public void filter(ContainerRequestContext requestContext) throws IOException {
MyObject myObject = new MyObject();
requestContext.setProperty("myObject", myObject);
}
And I am trying to read it in the business logic like :
#GET
#Path("/custom")
public String data(#Context ContainerRequestContext crc) {
Object pco = crc.getProperty("myObject");
}
I am using this approach from the example shared in : How to inject an object into jersey request context?
However I am getting the ContainerRequestContext crc as null. Can someone tell me what I could be doing wrong ?
I have tested the exact code asked in the question which works as it is with following setup:
spring-boot-starter-parent: 2.3.4.RELEASE
spring-boot-starter: inherited from parent
spring-boot-starter-jersey: inherited from parent
which evaluates to Spring 5.2.9.RELEASE, Jersey 2.30.1
Arquillian with Jersey can work.
I have UI object that wraps JPA entity and in constructor of that UI object I do lazy loading of some properties. In that same constructor I need to know what JsonView is currently active so I dont lazy load some fields that are not needed if say its the List view.
Is there way to find out from constructor what is current active JsonView at runtime. Or is there any other way to achieve what I described above.
My current plan
create custom serializer that during serialization will call setJsonView(Class jsonView) of the object that it serializes. All my objects that serialized will have to support that method. Inside that metid I can do lazy loading based on now known json view. Something like this:
public class JsonViewSerializer extends JsonSerializer<BaseSerializableEntity> {
#Override
public void serialize(BaseSerializableEntity value, JsonGenerator jgen, SerializerProvider provider) throws IOException, JsonProcessingException {
value.setJsonView(provider.getSerializationView());
// need to pass serialization to base class...
}
}
Currently active view is accessible via context object (SerializerProvider or DeserializationContext), using method getActiveView().
Assuming I have the following object
public class DataObjectA {
private Stream<DataObjectB> dataObjectBStream;
}
How can I serialize them using Jackson?
As others have pointed out, you can only iterate once over a stream. If that works for you, you can use this to serialize:
new ObjectMapper().writerFor(Iterator.class).writeValueAsString(dataObjectBStream.iterator())
If you're using a Jackson version prior to 2.5, use writerWithType() instead of writerFor().
See https://github.com/FasterXML/jackson-modules-java8/issues/3 for the open issue to add java.util.Stream support to Jackson. There's a preliminary version of the code included. (edit: this is now merged and supported in 2.9.0).
Streaming support feels like it would work naturally/safely if the stream is the top level object you were (de)serializing, eg returning a java.util.stream.Stream<T> from a JAX-RS resource, or reading a Stream from a JAX-RS client.
A Stream as a member variable of a (de)serialized object, as you have in your example, is trickier, because it's mutable and single use:
private Stream<DataObjectB> dataObjectBStream;
Assuming it was supported, all of the caveats around storing references to streams would apply. You wouldn't be able to serialize the object more than once, and once you deserialized the wrapping object presumably it's stream member would retain a live connection back through the JAX-RS client and HTTP connection, which could create surprises.
You don’t.
A Stream is a single-use chain of operations and never meant to be persistent. Even storing it into an instance field like in your question is an indicator for a misunderstanding of it’s purpose. Once a terminal operation has been applied on the stream, it is useless and streams can’t be cloned. This, there is no point in remembering the unusable stream in a field then.
Since the only operations offered by Stream are chaining more operations to the pipeline and finally evaluating it, there is no way of querying its state such that it would allow to create an equivalent stream regarding its behavior. Therefore, no persistence framework can store it. The only thing a framework could do, is traversing the resulting elements of the stream operation and store them but that means effectively storing a kind of collection of objects rather than the Stream. Besides that, the single-use nature of a Stream also implies that a storage framework traversing the stream in order to store the elements had the side-effect of making the stream unusable at the same time.
If you want to store elements, resort to an ordinary Collection.
On the other hand, if you really want to store behavior, you’ll end up storing an object instance whose actual class implements the behavior. This still works with Streams as you can store an instance of a class which has a factory method producing the desired stream. Of course, you are not really storing the behavior but a symbolic reference to it, but this is always the case when you use an OO storage framework to store behavior rather than data.
I had below class having 2 elements one of them was Stream, had to annotate the getterStream method with#JsonSerializer and then override Serialize method, produces stream of JSON in my Response API:
public class DataSetResultBean extends ResultBean
{
private static final long serialVersionUID = 1L;
private final List<ComponentBean> structure;
private final Stream<DataPoint> datapoints;
private static class DataPointSerializer extends JsonSerializer<Stream<DataPoint>>
{
#Override
public void serialize(Stream<DataPoint> stream, JsonGenerator gen, SerializerProvider serializers) throws IOException, JsonProcessingException
{
gen.writeStartArray();
try
{
stream.forEach(dp -> serializeSingle(gen, dp));
}
catch (UncheckedIOException e)
{
throw (IOException) e.getCause();
}
finally
{
stream.close();
}
gen.writeEndArray();
}
public synchronized void serializeSingle(JsonGenerator gen, DataPoint dp) throws UncheckedIOException
{
try
{
gen.writeStartObject();
for (Entry<DataStructureComponent<?, ?, ?>, ScalarValue<?, ?, ?>> entry: dp.entrySet())
{
gen.writeFieldName(entry.getKey().getName());
gen.writeRawValue(entry.getValue().toString());
}
gen.writeEndObject();
}
catch (IOException e)
{
throw new UncheckedIOException(e);
}
}
}
public DataSetResultBean(DataSet dataset)
{
super("DATASET");
structure = dataset.getMetadata().stream().map(ComponentBean::new).collect(toList());
datapoints = dataset.stream();
}
public List<ComponentBean> getStructure()
{
return structure;
}
#JsonSerialize(using = DataPointSerializer.class)
public Stream<DataPoint> getDatapoints()
{
return datapoints;
}
}
This is the class that implements Writable ..
public class Test implements Writable {
List<AtomicWritable> atoms = new ArrayList<AtomicWritable>();
public void write(DataOutput out) throws IOException {
IntWritable size = new IntWritable(atoms.size());
size.write(out);
for (AtomicWritable atom : atoms)
atom.write(out);
}
public void readFields(DataInput in) throws IOException {
atoms.clear();
IntWritable size = new IntWritable();
size.readFields(in);
int n = size.get();
while(n-- > 0) {
AtomicWritable atom = new AtomicWritable();
atom.readFields(in);
atoms.add(atom);
}
}
}
I will really appreciate if one can help me understand how to invoke write and readFields method.
Basically I m failing to understand how to construct Test object in this case. Once the object is written to DataOutput obj, how do we restore it in DataInput object. This may sound silly, but am a newbie to Hadoop and have been assigned a project that uses Hadoop. Please help.
Thanks!!!
Basically I m failing to understand how to construct Test object in this case.
Yup, you're missing the point. If you need to construct an instance of Test and populate atoms, then you need to add a constructor to Test:
public Test(ArrayList<AtomicWritable> atoms) {
this.atoms = atoms;
}
or you need to use the default constructor and add a method or a setter that lets you add items to atoms or set the value of atoms. The latter is actually pretty common in the Hadoop framework, to have a default constructor and a set method. cf., e.g., Text.set.
You don't call readFields and write; the Hadoop framework does that for you when it needs to serialize and deserialize inputs and outputs to and from map and reduce.
in velocity, when you do $object.variable if it not be able to find the getter function to
access it or the getter returns a null. it will just show $object.variable explicitly on the page
I know there is a quiet reference, but I don't want to add ! sign to thousands of variables.
I have tried InvalidReferenceEventHandler, NullValueHandler they all didn't get called.
I wander is there a specific type of Eventhandler for this.
Many thanks
The above seems to be a valid choice as well. However here is another option:
public class AppSpecificInvalidReferenceEventHandler implements
InvalidReferenceEventHandler
{
private static final Logger LOGGER =
Logger.getLogger(AppSpecificInvalidReferenceEventHandler.class);
#Override
public Object invalidGetMethod(Context context, String reference,
Object object, String property, Info info)
{
reportInvalidReference(reference, info);
return "";
}
#Override
public boolean invalidSetMethod(Context context, String leftreference,
String rightreference, Info info)
{
reportInvalidReference(leftreference, info);
return false;
}
#Override
public Object invalidMethod(Context context, String reference, Object object,
String method, Info info)
{
if (reference == null) {
reportInvalidReference(object.getClass().getName() + "." + method, info);
} else {
reportInvalidReference(reference, info);
}
return "";
}
private void reportInvalidReference(String reference, Info info)
{
LOGGER.info("REFRERENCE: " + reference + " Info <" + info + ">");
}
}
You'll also need to add the following to your velocity.properties file:
eventhandler.invalidreferences.class=path.to.package.AppSpecificInvalidReferenceEventHandler,org.apache.velocity.app.event.implement.ReportInvalidReferences
You might be surprised at the results though, so it will likely need fine-tuning dependent upon your needs.
I'm basing this off of Engine-1.7 code.
It seems that when an invalid method is called that the utility method EventHandlerUtil.invalidGetMethod is called. This method creates a new InvalidGetMethodExecutor (this is an inner class on InvalidReferenceEventHandler). Eventually this chains down into a call to invalidReferenceHandlerCall which eventually iterates over any handlerIterators which have been defined. Unfortunately I don't know enough about the internals of Velocity to tell you how to inject these values though. My guess is that the user list will suggest a way to override this behavior or a suggestion will be to use / implement a custom tool.
Edit:
According to the Developer Guide you can do the following. You'll need to write some code to deal with it, but it shouldn't be too difficult:
Pluggable Introspection
runtime.introspector.uberspect = org.apache.velocity.util.introspection.UberspectImpl
This property sets the 'Uberspector', the introspection package that handles all introspection strategies for Velocity. You can specify a comma-separated list of Uberspector classes, in which case all Uberspectors are chained. The default chaining behaviour is to return the first non-null value for each introspection call among all provided uberspectors. You can modify this behaviour (for instance to restrict access to some methods) by subclassing org.apache.velocity.util.introspection.AbstractChainableUberspector (or implementing directly org.apache.velocity.util.introspection.ChainableUberspector). This allows you to create more interesting rules or patterns for Uberspection, rather than just returning the first non-null value.