guys! I am developing a web application and I decided to use Jackson as my JSON processing framework.
In request data that I am willing to send; let's say the POJO looks like this:
data class JSONEnvelope(
#JsonProperty("obj1")
val obj1: Obj1,
#JsonProperty("obj2")
val obj2: Obj2)
which get serialized like this:
{
"obj1":{...},
"obj2":{...}
}
but I need to add some metadata to that object, let's say fields meta1 and meta. I thought that #JsonAppend would solve my problem, but I am using Jackson together with Jersey, so I am not serializing objects manually, so I cannot use writer.withAttribute("...", ...).
I am aware of this thread, but there is no answer that kinda satisfy my needs, because I think, that writing a custom serializer is a bit overkill for this, moreover if I do not have a mechanism to "serialize the rest of the original object". I'd be glad for any ideas
The solution in the answer you cited, which adds a mixIn to a the ObjectMapper then uses the ObjectWriter to configure it, is a good solution.
For Jersey, which calls ObjectMapper.writerFor and therefore prevents you from calling withAttribute in order to configure the ObjectWriter, one alternative is to add the attribute to the ObjectWriter before returning it from writerFor. I suggest subclassing ObjectMapper and overriding the various writerFor methods, adding the necessary attribute at that point. You can then get Jersey to use that ObjectMapper by registering it as a JAX-RS Provider: see the various annotations in javax.ws.rs to get started on this. This answer gives an example of what to do.
Related
What serializer is Entity.json(T entity) using to serialize/deserialize objects? Is it somehow possible to use a custom serializer?
In my case the serialization is wrong because my object contains fields with the Guava Optional data type and absent values are returned as {"present":false} instead of null.
The JSON serializer isn't specified by JAX-RS, it depends on your configuration. For example, Jersey JAX-RS allows several (https://jersey.java.net/documentation/latest/media.html), including
MOXy
Java API for JSON Processing (JSON-P)
Jackson
Jettison
But a better solution is not to use Optional (either Guava or Java 8) for fields. See http://blog.joda.org/2014/11/optional-in-java-se-8.html
My only fear is that Optional will be overused. Please focus on using
it as a return type (from methods that perform some useful piece of
functionality) Please don't use it as the field of a Java-Bean.
Not directly solving your problem. I suggest you use Googles Gson as a parser. It is very flexible and configurable.
Tutorial
It also skips blank fields so the json size is not too large.
Ideally, it would look much like this:
List<String> props = objectMapper.getKnownProperties(MyPojo.class);
Alas, there is no such method. An approach that would generally work is to explicitly set Include.ALWAYS as the ObjectMapper's default, instantiate an instance of the class reflectively, convert it to a map, and examine the keyset. However, classes can still override the ObjectMapper's include behavior given annotations.
Is there a more elegant approach? At the very least, is there a way to override class annotations using the object mapper?
Edit:
Just to clarify, these pojos/javabeans/DTOs are designed for use with Jackson and are already rigged with annotations to result in specific serialization behavior. It just so happens that I need to dynamically know what I might end up with up-front, ideally without duplicating the information already available to jackson. That said, if another framework offers this functionality, I'd be curious to know. :)
With Jackson, you can introspect a class and get the available JSON properties using:
// Construct a Jackson JavaType for your class
JavaType javaType = mapper.getTypeFactory().constructType(MyDto.class);
// Introspect the given type
BeanDescription beanDescription = mapper.getSerializationConfig().introspect(javaType);
// Find properties
List<BeanPropertyDefinition> properties = beanDescription.findProperties();
If you have #JsonIgnoreProperties class level annotations, check this answer.
Depending on your exact needs, JsonFilter could also work (f.ex see http://www.cowtowncoder.com/blog/archives/2011/09/entry_461.html).
And for more advanced cases, BeanSerializerModifier does give you access to actual list of BeanPropertyWriters, which represent individual properties POJO has. From that, you could write a wrapper that enables/disables output dynamically.
Or perhaps you can even combine approaches: modifier to get list of possible property names; then FilterProvider to dynamically add filter. Benefit of this would be that it is a very efficient way of implementing filtering.
It's possible to ignore all annotations by using a dummy AnnotationIntrospector:
objectMapper.setAnnotationIntrospector(new AnnotationIntrospector(){
#Override public Version version() {
return Version.unknownVersion();
}
});
Perhaps you could use Jackson's JSON Schema module to generate a schema for a class, then inspect the schema.
As you could see from this question, the response that worldweather return is not quite pretty. They return array of current weather conditions (I try to understand why did they made it that way, there couldn't be more then one weather condition in a specific place, as far as I know...), so it breaks the unmarshalling via annotations,
#JsonProperty("current_condition")
private CurrentWeatherData currentWeatherData;
because Jackson actually awaits a collection or an array. Now, can I somehow to tell the unmarshaller to use the first array member, and if yes, how do I do that?
There is no such annotation. You will probably want a custom deserializer to handle this special case.
For Jackson 2.2 there will be support for separate Converters, which could work here (as they only work on Java objects). But since it is not yet released, custom deserializer is probably the way to go.
I have an object that I would like to serialize with an attribute in one part of my program, but without in a different part. I also have an ObjectMapper which is extensively customized that I use for both serializations. My first inclination was to use a Mixin to tweak if the attribute is shown, but it seems that you can only put those on the ObjectMapper and not on a reader returned by the ObjectMapper. Basically the code I would like to be able to write would look like the following.
ObjectMapper myMapper = new ObjectMapper(); // in reality there is a lot of customization
Foo foo = myMapper.reader().withMixin(Foo.class, FooMixin.class).readValue(jsonParser, Foo.class);
Correct. You can not change mix-ins on-the-fly, however: since they are used for introspection of (de)serializers, and results (actual (de)serializers) are cached, they must be added as part of the initial configuration.
This is why neither ObjectReader nor ObjectWriter exposes methods to change mix-ins: they only allow changing of things that can be dynamically changed, on per-call basis.
But perhaps mix-ins are not the best way to do this: have you considered using JSON Views instead? Active view in use can be changed separately for each (de)serialization.
Actually, you can configure mixins for serialization or deserialization (or both of course):
objectMapper.getSerializationConfig().addMixInAnnotations(Rectangle.class, MixIn.class);
objectMapper.getDeserializationConfig().addMixInAnnotations(Rectangle.class, MixIn.class);
http://wiki.fasterxml.com/JacksonMixInAnnotations
I am using Axis to call a SOAP-based web service. I'm then trying to serialize the returned remote object as JSON, using the Google Gson library.
The serialization to JSON fails, with Gson complaining that "there are multiple elements with the name __equalsCalc()).
When I inspect the returned object in my IDE (Eclipse), I can see that this is true -- the returned object has three members called __equalsCalc() and another three called __hashCode.
I know from looking around that these are added by WSDL2Java (I think) in order to avoid recursion. My question is, why are there THREE of each? And how can I get the serializer to ignore these? They're not actually part of the object's definition (it's called a RemoteProject, for reference). Can I do something hackish like cast the RemoteProject to a RemoteProject to get it to drop those members?
This turns out to be not too hard to solve. I have multiple copies of the same instance var because the class being serialized is shadowing fields of the same name from superclasses. Since I don't care about these fields, the best approach in Gson is to write a custom ExckusionStrategy which can selectively ignore fields based on their name:
http://google-gson.googlecode.com/svn/trunk/gson/docs/javadocs/com/google/gson/ExclusionStrategy.html
I don't know GSon.
With Jackson, you can annotate properties (i.e - fields that have getters/setters according to Java bean convention) with #JsonIgnore.
This way you can prevent issues like recursion/no matching setter or getter and so on...
Try to find out if you have the same at GSon or use Jackson.