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!
Related
Given an arbitrary class, is it possible for Jackson to provide a list of the fields needed to serialize and deserialize it?
Jackson's serialization rules are complex. I'd like to determine at runtime what the Jackson JSON structure is expected for an arbitrary class (both serialization and deserialization). My current planned implementation is to look for an #JsonConstructor constructor method and parse its arguments. If that's not there, look for annotations on other methods, and otherwise, use the list of member variables. I'll recurse the algorithm for any non-primitive field types.
The end goal is to create documentation for service endpoints.
Yes, you can use Jackson's introspection. This has the benefit that all annotations are applied as expected, and result should be exactly as Jackson "sees" the type you want information about.
There are at least two ways to do that:
Request introspection via SerializationConfig (or, DeserializatonConfig), to get a BeanDescription
Use callback/visitor based approach by calling ObjectMapper.acceptJsonFormatVisitor(type, visitor)
First method is usually simpler:
JavaType type = mapper.constructType(MyBean.class);
BeanDescription desc = mapper.getSerializationConfig()
.introspect(type);
but latter is useful for tasks like generation of schemas (JSON Schema, XML Schema, protoc, thrift).
I realize this has probably been asked a hundred times but I have searched a lot and can't find specifically what I'm looking for.
Here is what I'd like. Given a string data, I'd like to deserialize into an object obj that doesn't have all the fields predefined. I'd like to just be able to ask for the fields I want such as obj.getString("stringFieldName") or obj.getInt("intFieldName"). I already have gson being used for other things so if it is possible with gson that would be great although not opposed to using another library.
The 'standard' Android JSON library (since API 1) already provides such untyped access.
See JSONObject, eg. getInt:
Returns the value mapped by name if it exists and is an int or can be coerced to an int, or throws otherwise.
Unless needing the JSON mapped onto a 'native' Java collection type this is probably the simplest way to achieve the request. It doesn't require any additional libraries.
With Jackson library you can annotate data model class with
#JsonIgnoreProperties(ignoreUnknown = true)
and the jacksonconverter will just parse only these fields that you defined. Other will be ignored.
Have you tried using Retrofit from Square? It works with GSON and Java Annotations and it's super easy to set up.
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. =/
I've a class CONTAINER, that contains a List .
BaseClass is not an abstract class, but there is 2 subtypes of BaseClass : BaseClassA and BaseClassB which each have extra fields.
BaseClass has an attribut enum Type, from which i can determinate if an object is BaseClass, BaseClassA or BaseClassB and that i want to use as a discriminator.
How can i tell Jackson the discriminator so when it deserialize the json string, it builds the correct object. At the moment every object is instancied as a BaseClass so i cannot cast it in my java code.
The same way as #DiscriminatorFormula & #DiscriminatorValue work for hibernate and entities
I've found this question : How can I polymorphic deserialization Json String using Java and Jackson Library? which is kinda close but here the user only wants the basic type.
Guessing you have probably solved this but if not check out JsonTypeInfo as a way to annotate classes with subtypes for desrialization. This link http://programmerbruce.blogspot.com/2011/05/deserialize-json-with-jackson-into.html has a good explanation that is still valid. If you can't annotate your classes you can use configuration to set up mix-ins (see https://github.com/FasterXML/jackson-docs/wiki/JacksonMixInAnnotations) that allow you to add annotations to existing classes.
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.