Is it possible to serialize an object with no fields in Jackson using only annotations? When I attempt to serialize such an object with no annotations I get:
Exception in thread "main" com.fasterxml.jackson.databind.JsonMappingException: No serializer found for class [redacted].SubjectObjectFeatureExtractor and no properties discovered to create BeanSerializer
I have examined the list of Jackson annotations without seeing a way to annotate the class as having no serializable data. I tried putting #JsonCreator on the empty constructor (not expecting it to work, since it's a deserialization annotation), and I got the same error. There are no accessors or fields to put #JsonProperty on. Any ideas?
Update: The reason for this is that I have a list of objects which represent transformations which can be applied to a certain type of data. Some of these transformations are defined by parameters which needs to be serialized, but some of these are parameter-less (the data-less objects in question). I'd like to be able to serialize and deserialize a sequence of these transformations. Also, I'm using DefaultTyping.NON_FINAL so that the class name will be serialized.
Update: An example class would be
class ExtractSomeFeature implements FeatureExtractor<SomeOtherType> {
public void extractFeature(SomeOtherType obj, WeightedFeatureList output) {
// do stuff
}
}
I don't particularly care how the JSON for this looks like, as long as I can deserialize List<FeatureExtractor>s properly. My impression is that using default typing, the expected JSON would be something like:
['com.mycompany.foo.ExtractSomeFeature', {}]
Other sub-classes of FeatureExtractor would have real parameters, so they would presumably look something like:
[`com.mycompany.foo.SomeParameterizedFeature', {some actual JSON stuff in here}]
I think I could use #JsonValue on some toJSONString() method to return {}, but if possible I'd like to hide such hackery from end-users who will be creating FeatureExtractor sub-classes.
You have to configure your object mapper to support this case.
ObjectMapper objectMapper = ...
objectMapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
The documentation of this feature can be found here : Fail on empty beans
Feature that determines what happens when no accessors are found for a
type (and there are no annotations to indicate it is meant to be
serialized). If enabled (default), an exception is thrown to indicate
these as non-serializable types; if disabled, they are serialized as
empty Objects, i.e. without any properties.
The answer to disable SerializationFeature.FAIL_ON_EMPTY_BEANS is global, and you therefore might not wish to apply it.
The answer to add any serialisation annotation showed the correct (as in: the Javadoc of SerializationFeature.FAIL_ON_EMPTY_BEANS suggests it) way to fix it, but only with a hackish or an unrelated annotation.
By merely adding…
#JsonSerialize
… to my class (not even parenthesēs after it, lest alone arguments!) I was able to produce the same effect (as, again, indicated by the Javadoc of SerializationFeature.FAIL_ON_EMPTY_BEANS).
Adding the following annotation onto the class seems to solve the problem:
#JsonAutoDetect(fieldVisibility=JsonAutoDetect.Visibility.NONE)
Adding an unrelated annotated like
#JsonRootName("fred")
also seems to fix it. This seems to match the claim in the JIRA ticket that adding any Jackson annotation to the class will prevent the exception. However, it appears adding annotations within the class does not.
Not sure I get your question, but perhaps you want JsonInclude.Include.NON_DEFAULT, JsonInclude.Include.NON_NULL, or JsonInclude.Include. NON_EMPTY.
Related
We use JSON serialization with Jackson to expose internal state of the system for debugging properties.
By default jackson does not serialize transient fields - but I wish to serialize them as well.
How can I serialize these fields?
One way I know is to supply a getters for these fields - but I don't want to do that, as I have some getX methods that I don't want to be invoked ( for instance, there are some getters that change the objects state ).
I know I could create an annotation, but I really want to avoid it.
So my question is:
Is there a way to setup jackson to serialize all the objects fields? include transient ones.
My solution with Jackson 2.4.3:
private static final ObjectMapper mapper =
new ObjectMapper(){{
Hibernate4Module module = new Hibernate4Module();
module.disable(Hibernate4Module.Feature.USE_TRANSIENT_ANNOTATION);
registerModule(module);
}};
I don't think Jackson supports any type of configuration to enable it to serialize a transient field. There's an open issue to add that feature, but it's old and hasn't been addressed (as far as I can tell): http://jira.codehaus.org/browse/JACKSON-623
So my question is: Is there a way to setup jackson to serialize all
the objects fields? include transient ones.
So to answer your question, no.
Some other Java JSON tools, such as GSON do support a configuration option to serialize transient fields. If you can use another tool, you might look into that (for GSON, see: https://sites.google.com/site/gson/gson-user-guide).
To expand a little, you might try a different approach.
First, You shouldn't try to serialize a transient field. After all the definition of transient is "don't serialize this." Nevertheless I can think of a few specific situations where it might be necessary, or at least convenient (like when working with code you can't modify or such). Still, in 99% of cases, the answer is don't do that. Change the field so that it's not transient if you need to serialize it. If you have multiple contexts where you use the same field, and you want it serialized in one (JSON, for example), and not serialized in another (java.io, for example) then you should create a custom serializer for the case where you don't want it, rather than abuse the keyword.
Second, as to using a getter and having "some getters that change the objects state," you should try to avoid that too. That can lead to various unintended consequences. And, technically, that's not a getter, that's a setter. What I mean is, if it mutates state, you've got a mutator (setter) rather than accessor (getter), even if you name it following the "get" convention and return some stuff.
You can create a custom getter for that transient field and use #XmlElement attribute. It doesn´t matter the name of that getter.
For example:
public class Person {
#XmlTransient private String lastname;
#XmlElement(name="lastname")
public String getAnyNameOfMethod(){
return lastname;
}
}
Another way to let Jackson serialize property is to add #JsonProperty annotation above it.
I guess it's better approach cause you do not need to disable default behaviour for all #Transient fields, like in Gere's answer.
I'm doing a very simple thing that should just work, IMO. I've got a resource like:
#GET
#Produces(MediaType.APPLICATION_JSON)
#Path("{nodeType}/{uuid}")
public Object getResourceInfo(#PathParam("nodeType") String nodeType,
#PathParam("uuid") String uuid,
#Context SecurityContext authority) { ...
Note I'm returning type Object. This is because depending on the call (here depending on the nodeType argument) I want to return a different concrete class (which will always be #XmlRootElement) and have that get marshalled out into the response.
However, this does not work. I get exception like:
Exception Description: A descriptor for class com.mycompany.XmlElementTypeInstance was not found in the project. For JAXB, if the JAXBContext was bootstrapped using TypeMappingInfo[] you must call a marshal method that accepts TypeMappingInfo as an input parameter.
If I change Object to a single subclass, it works. But I want it to be able to handle any subclass, XmlElementTypeInstance, XmlElementTypeInstance2, etcetc.
I tried making a common interface from which all of the XmlElementTypeInstance subclasses derive, but then I only get those properties in the interface, not the extra properties in the subclasses. Playing with #XmlElementRef and adding all possible properties to the common interface is extremely ugly and can't work quite correctly to generate the JSON I want, so please don't suggest that. =)
Is there any way to do this? It seems like simple, basic, necessary functionality... any other REST framework I've used, no problem...
The solution it turns out is simple (had to read the JSR instead of the actual Jersey docs, however!)
Instead of returning Object, returning Response (section 3.3.3 of JSR 339) with the object set as the entity forces the implementation to pick an appropriate MessageBody{Writer,Reader} at runtime.
return Response.ok().entity(<the object>).build();
Lost way too much time on this. Hope it helps someone later. =/
(Disclaimer: Extreme oversimplification. The actual scenario is considerably more complex.)
Say I have two systems, Producer and Consumer. Their code is completely independent, aside from a single shared interface:
public interface Thing {
String getName();
String getDescription();
int getPrice();
}
The idea is that Producer creates a bunch of data and sends it as JSON over HTTP. Producer has a bunch of implementations of Thing, each with additional pieces of metadata and stuff required in the data generation process.
As it's undesirable for Producer to have any kind of knowledge of Jackson/serialization aside from a thin layer at the very top, serialization attributes should be kept out of the Thing implementations. Due to the amount of implementation being very likely to grow in the future, having mixins for all of them quickly becomes unsustainable. It was believed to be sufficient to apply annotations to the Thing interface itself.
The first simple approach was a #JsonSerialize annotation on the interface. At first, that seemed to work, but resulted in a problem. Some of the implementations of Thing are enums, resulting in Jackson simply serializing them as their name instead of the fields defined in the interface.
Some googling revealed the following annotation:
#JsonFormat(shape= JsonFormat.Shape.OBJECT)
While it did indeed solve the problem by serializing the fields instead of the name, it did it too well as it also began serializing the implementation-specific public fields not defined in the Thing interface, resulting not only in information leak, but also failed deserialization in Consumer due to the data containing unknown entries.
As further googling didn't yield any results, the only solution I can think of is marking all those fields as ignorable, something that is extremely undesirable due to the previously mentioned reasons.
Is there any way, simply by altering the interface itself and its annotations, to enforce that exactly those fields, no more, no less, should be serialized both when it comes to classes and enums?
I have this issue when I was working with Jackson. The deserialization fails because, during deserialization, Jackson is unable to find the polymorphic reference type.
You should be annotating your interface with #JsonTypeInfo.
Something like:
#JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, include = JsonTypeInfo.As.PROPERTY, property = "class")
There isn't much of code in your question and hence this answer.
Usually you should be able to force use of certain type with:
#JsonSerialize(as=Thing.class)
and similarly with #JsonDeserialize.
Does this not work with enums?
for example I have 20 entity classes in current Spring application, only one need to map to JSON object, so here are two questions:
Is it necessary to place #JsonIgnoreProperties(ignoreUnknown=true) to all other classes?
If I choose org.codehaus.jackson for JSON handler, is there a chance that jackson will go through all entity classes to try to make a mapping? I have a
org.codehaus.jackson.map.JsonMappingException: Infinite recursion (StackOverflowError)
exception thrown but the collection object mentioned in the log has been already marked as #JsonIgnore, even the whole class is marked as #JsonIgnoreProperties(ignoreUnknown=true). So what could make it like above?
If you try to map a class as a JSON object using Jackson, all the primitives will be fine. However, jackson will try to map any objects which are in that object you're mapping into JSON objects. So any Class that is a field member of the class you're mapping with JSON will either need to be able to be mapped to a JSON (and any object fields it has) or you will need to ignore those object fields in the original class.
Also, if you have any recursive mappings (like a User has a Team, and the Team has a list of users) that can cause an infinite loop. Jackson 2 has some great solutions to help with that.
I'm using Jackson to deserialize some JSON into Java POJOs. I register the MrBean module with my object mapper, so all I have to do is define a bunch of interfaces, and the POJOs are generated automagically, based on those interfaces.
I would like to have a Credentials interface with various types of credentials that extend it, e.g. UsernamePasswordCredentials and CertificateFileCredentials.
Doing this without any annotations or other incantations to try to make it work gives me the following error in my unit test:
org.codehaus.jackson.map.exc.UnrecognizedPropertyException: Unrecognized field "username" (Class org.codehaus.jackson.generated.SCRUBBED.Credentials), not marked as ignorable
at [Source: java.io.StringReader#e0b6f5; line: 32, column: 29] (through reference chain: HostConfiguration["hostDefinitions"]->HostDefinition["credentials"]->Credentials["username"])
I've also followed the instructions at another StackOverflow post, and I'm getting the same error.
The error makes sense; Jackson is trying to map the contents of my JSON file to an empty interface. However, I (naively, perhaps) expected Jackson to look for interfaces that extend the base Credentials interface and try to match up the fields in those interfaces to the fields it found in the JSON object.
I've seen some examples at the Jackson wiki that make use of meta-information in the JSON object, e.g. decorating an object with "#class":"foo.bar.CertificateFileCredentials", but I'd prefer to avoid any of that since my JSON input will be generated automatically by other services, and those other services shouldn't have to know anything about the internals of my service.
Thanks!
How would you define actual implementation classes? As additional interfaces? Those should get generated correctly; but the problem is during deserialization: there must be some way for deserializer to find out actual type to use, if there are multiple choices.
For this, #JsonTypeInfo is recommended to be used as you have noticed.
Actually, the technique would work well for your purposes too, even though you don't control the service that generates the JSON.
Saving the class name is a nice easy default when using #JsonTypeInfo but Jackson lets you customize this to your liking.
For example, suppose the service generates JSON that looks like this:
{ meows: 400, furColor: "green", species: "cat" }
Then you can define these interfaces to convert it properly.
#JsonTypeInfo(use=JsonTypeInfo.Id.NAME, include=JsonTypeInfo.As.PROPERTY,property="species")
#JsonSubTypes({
#JsonSubTypes.Type(value=Feline.class, name="cat")
})
public interface Animal {
public String getFurColor();
}
#JsonTypeName("cat")
public interface Feline extends Animal {
#JsonProperty("meows") // just to have an example of a renamed property...
public long getMeowingVolumeInDecibels();
}
Then you should just automatically get the right java type at runtime when deserializing, as well as automatically generate the "species" property depending on the runtime type. Hope that helps!