I want to use method canDeserialize, because at moment deserialization i want to get type class for apply at custom deserialization, as about next example :
public T deserialize(byte[] bytes) throws SerializationException {
bolean isAccount = this.objectMapper.canDeserialize(??????).
T t = null;
if(isAccount)
t = (T)this.objectMapper.readValue(bytes,Account.class);
else
t = (T) this.objectMapper.readValue(bytes, 0, bytes.length, new TypeReference<Object>(){});
return t;
}
In this case Account class have annotation #JsonDeserialize for a custom deserialization .
To directly answer your question, this is how you use the canDeserialize method:
final ObjectMapper mapper = new ObjectMapper();
mapper.canDeserialize(mapper.constructType(Bean.class));
Where Bean is the name of your Java class to be checked.
But wait, you are trying to solve the wrong problem. You are struggling with the logic for your method because it has not been designed properly. You are really asking too much of the Java runtime (and Jackson library), by trying to make them infer all the required information about the type to be instantiated (based on the parameterized return). To solve this you should include the class representing the type to be deserialized as a parameter to the method, greatly simplifying the logic:
public <T> T deserialize(byte[] bytes, Class<T> clazz) throws IOException,
JsonProcessingException {
return new ObjectMapper().readValue(bytes, clazz);
}
At this point you have probably realized that the method above provides no additional functionality over just calling ObjectMapper.readValue directly, so ... just do that! No need to define custom methods, just use ObjectMapper and you are good to go. Keep in mind that you do not need to do anything explicit to trigger custom deserialization of classes. The Jackson runtime automatically detects when a class has a custom deserializer and invokes it.
Related
I have already posted something similar but I still trying to zero in on my problem.
Thanks for bearing with me.
It would appear that jackson is not calling a mixin as it should and I can't tell why.
"Element" is an interface not a class. It is normally instantiated with a static factory call as shown in the mixin (below). The way I understand it, when jackson sees the interface: Element.class it should look up the mixin then execute the method that has the #JsonCreator annotation. None of this is happening. If it were, I would see output from the logger. Instead, as one can see in the error message (way below), jackson is trying to treat my interface as a class and can't.
Why isn't my mixin working?
Here's the mixin:
public class ElementMixin {
private static Logger log = LoggerFactory.getLogger(ElementMixin.class);
#JsonCreator
public static Element create() {
log.error("Element==>");
return FhirFactory.eINSTANCE.createElement();
}
}
Here's how I register it with the mapper:
ObjectMapper mapper = new ObjectMapper();
mapper.addMixIn(Element.class, ElementMixin.class);
Here's how I am running things:
// Instantiate my interface, put some data in and serialize.
Element ela = FhirFactory.eINSTANCE.createElement();
ela.setId("CBAEL");
StringWriter writer = new StringWriter();
mapper.writeValue(writer, ela);
// Now try to deserialize into a new instance.
StringReader reader = new StringReader(writer.toString());
Element elp = mapper.readValue(reader, Element.class);//Error thrown
assertNotNull(elp);
The error:
com.fasterxml.jackson.databind.JsonMappingException: Can not construct
instance of fhir.Element, problem: abstract types either need to be
mapped to concrete types, have custom deserializer, or be instantiated
with additional type information at [Source:
java.io.StringReader#4fe533ff; line: 1, column: 1] at
com.fasterxml.jackson.databind.JsonMappingException.from(JsonMappingException.java:255)
at
com.fasterxml.jackson.databind.DeserializationContext.instantiationException(DeserializationContext.java:1007)
at
com.fasterxml.jackson.databind.deser.AbstractDeserializer.deserialize(AbstractDeserializer.java:150)
at
com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:3807)
at
com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:2844)
at
gov.nist.forecast.fhir.resources.IndexResourceTest.testParametersJSON(IndexResourceTest.java:173)
Mix-ins only associate annotations; they can not and do not add any fields or methods -- no bytecode generation or manipulation is added. So while you can add annotations to indicate methods that already exist in target (including static factory methods) should be used, nothing (aside from annotations) defined in mix-in will ever get called or used.
I have a type called OptionalField<T> which can be either empty(), defined(value) (like a normal optional) or nullValue(default) (represent a default value in JSON that could be anything like "n/a" or such).
My problem is with Jackson, because I need to create a custom serializer, and deserialiser capable of identifying the generic type and finding the appropriate default serializer, deserializer. I had not much trouble creating the serializer with a Contextual interface since it provides a property and Serializer provider
public JsonSerializer<?> createContextual(SerializerProvider prov, BeanProperty property) throws JsonMappingException {
...
JsonSerializer<Object> serialiser = prov.findValueSerializer(property.getType().containedType(0).getRawClass(), property);
...
}
But the deserializer is something else, I cannot find a way to identify the type and and find the default deserializer. Do you know how I could do that ? I read some things about BeanDeserializers but I don't think it answers to my problem.
Update
I went through the library https://github.com/FasterXML/jackson-datatype-jdk8 to understand how they do it and it seems very low level manipulation (types and scala). Is there really no other way to do that ? Some higher way to use Jackson ? It really seems like a common use case to me (generic classes I mean) ?
Using the type parameters in a serializer/deserializer isn't all that common, in my experience. It's more complicated than it could be, due in part to how type parameters were patched on to Java from version 1.5. This makes it difficult to get right in anything but the simple cases. Even the serializer example you give looks like it would only work for unparameterised classes, since it's finding a serializer based only on the raw T (what if you had OptionalField<Set<SomeObject>> ?)
The jdk8 or guava datatype add-ons are the place to start. Yes, they may seem daunting, but that complexity is (mostly) there for a reason. I've adapted them to support serializing/deserializing some other Optional-like type myself (fj.Option), so it's certainly possible.
When you implement Deserializers, the findBeanDeserializer method is called with the context of where the property was defined- so here you should have the full type with all its parameters:
#Override
public JsonDeserializer<?> findBeanDeserializer(JavaType type, DeserializationConfig config, BeanDescription beanDesc)
throws JsonMappingException {
Class<?> raw = type.getRawClass();
if (raw == Option.class) {
JavaType[] types = config.getTypeFactory().findTypeParameters(type, Option.class);
JavaType refType = (types == null) ? TypeFactory.unknownType() : types[0];
JsonDeserializer<?> valueDeser = type.getValueHandler();
TypeDeserializer typeDeser = type.getTypeHandler();
// [Issue#42]: Polymorphic types need type deserializer
if (typeDeser == null) {
typeDeser = config.findTypeDeserializer(refType);
}
return new FJOptionDeserializer(type, refType, typeDeser, valueDeser);
}
return super.findBeanDeserializer(type, config, beanDesc);
}
}
Here refType is the type of the parameter to Option, so we pass it to the constructor of the deserializer- i.e. each occurrence of an Option in classes analyzed by Jackson will get its own deserializer instance, customised with the parameters of the OptionalField type.
By and large, I copied the Optional implementation and it worked quite easily. The implementation of the OptionalDeserializer et al isn't the clearest (as it combines two cases in one class, imho confusingly).
I'm trying to code domain objects that can create themselves from other objects which implement the same interface. I'm also coding it so they can transform themselves into other implementations, basically simple domain transfer objects. I'm using jackson to automatically convert between implementations to reduce error prone boiler plate of manual object conversion.
It's probably easier to show with an example:
//base class
public abstract class DO<T extends Object> {
public abstract T toDTO();
public abstract DO<T> fromDTO(T t);
}
//concrete implementation
public class MyDO extends DO<MyDOInterface> implements MyDOInterface {
public MyDO fromDTO(MyDTO r){
ObjectMapper mapper = new ObjectMapper();
return mapper.convertValue(r, MyDO.class);
}
public MyDTO toDTO() {
ObjectMapper mapper = new ObjectMapper();
return mapper.convertValue(this, MyDO.class);
}
//getters and setters from MyDOInterface
}
Now this works fine when creating DTOs, but is a bit of a pain the other way around. To create my domain objects I'm having to do this:
MyDO myDO = new MyDO().fromDTO(aDTOInstance);
Which creates an empty object in order to call fromDTO(...) on it.
I've got a feeling I'm missing something simple that would either allow me to pass the DTO in a constructor or a static method to avoid this. Or even a factory method in DO itself but I can't work out what it is. Can anyone see a way of making this work?
Maybe have a look at #JsonCreator annotation: it allows you to mark constructors and (static) factory methods to be used. Specifically, so-called "delegating" creator like:
Another possibility when serializing would be #JsonValue, which allows certain conversions during serialization process.
I don't know if these help with specific problem, since you are doing more conversion than reading/writing JSON, but they seem related.
I'm trying to marshal a list: List<Pojo> objects via the Spring Rest Template.
I can pass along simple Pojo objects, but I can't find any documentation that describes how to send a List<Pojo> objects.
Spring is using Jackson JSON to implement the HttpMessageConverter. The jackson documentation covers this:
In addition to binding to POJOs and
"simple" types, there is one
additional variant: that of binding to
generic (typed) containers. This case
requires special handling due to
so-called Type Erasure (used by Java
to implement generics in somewhat
backwards compatible way), which
prevents you from using something like
Collection<String>.class (which does
not compile).
So if you want to bind data into a
Map<String,User> you will need to use:
Map<String,User> result = mapper.readValue(src, new TypeReference<Map<String,User>>() {});
where TypeReference is only needed to
pass generic type definition (via
anynomous inner class in this case):
the important part is
<Map<String,User>> which defines type
to bind to.
Can this be accomplished in the Spring template? I took a glance at the code and it makes me thing not, but maybe I just don't know some trick.
Solution
The ultimate solution, thanks to the helpful answers below, was to not send a List, but rather send a single object which simply extends a List, such as: class PojoList extends ArrayList<Pojo>. Spring can successfully marshal this Object, and it accomplishes the same thing as sending a List<Pojo>, though it be a little less clean of a solution. I also posted a JIRA in spring for them to address this shortcoming in their HttpMessageConverter interface.
In Spring 3.2 there is now support for generic types using the new exchange()-methods on the RestTemplate:
ParameterizedTypeReference<List<MyBean>> typeRef = new ParameterizedTypeReference<List<MyBean>>() {};
ResponseEntity<List<MyBean>> response = template.exchange("http://example.com", HttpMethod.GET, null, typeRef);
Works like a charm!
One way to ensure that generic type parameters are included is to actually sub-class List or Map type, such that you have something like:
static class MyStringList extends ArrayList<String> { }
and return instance of that list.
So why does this make a difference? Because generic type information is retained in just a couple of places: method and field declarations, and super type declarations. So whereas "raw" List does NOT include any runtime type information, class definition of "MyStringList" does, through its supertype declarations.
Note that assignments to seemingly typed variables do not help: it just creates more compile-time syntactic sugar: real type information is only passed with Class instances (or lib-provided extensions thereof, like JavaType and TypeReference in Jackson's case).
Other than this, you would need to figure out how to pass Jackson either JavaType or TypeReference to accompany value.
If I read the docs for MappingJacksonHttpMessageConverter right, you will have to create and register a subclass of MappingJacksonHttpMessageConverter and override the getJavaType(Class<?>) method:
Returns the Jackson JavaType for the
specific class. Default implementation
returns
TypeFactory.type(java.lang.reflect.Type),
but this can be overridden in
subclasses, to allow for custom
generic collection handling. For
instance:
protected JavaType getJavaType(Class<?> clazz) {
if (List.class.isAssignableFrom(clazz)) {
return TypeFactory.collectionType(ArrayList.class, MyBean.class);
} else {
return super.getJavaType(clazz);
}
}
I have solved this problem by using the following configuration:
private static final String POJO_ARRAY_LIST = PojoArrayList.class.getCanonicalName();
#Bean
public HttpMessageConverter<Object> httpMessageConverter() {
HttpMessageConverter<Object> httpMessageConverter = new MappingJackson2HttpMessageConverter() {
#Override
protected JavaType getJavaType(Type type, #Nullable Class<?> contextClass) {
JavaType javaType;
if (type != null && POJO_ARRAY_LIST.equals(type.getTypeName())) {
ObjectMapper objectMapper = new ObjectMapper();
TypeFactory typeFactory = objectMapper.getTypeFactory();
CollectionType collectionType = typeFactory.constructCollectionType(ArrayList.class, Pojo.class);
javaType = collectionType;
} else {
javaType = super.getJavaType(type, contextClass);
}
return javaType;
}
};
return httpMessageConverter;
}
where PojoArrayList is a final class that extends ArrayList<Pojo>.
I want to convert a JSON string into java object, but the class of this object contains abstract fields, which Jackson can't instantiate, and doesn't produce the object. What is the easiest way to tell it about some default implementation of an abstract class, like
setDefault(AbstractAnimal.class, Cat.class);
or to decide about the implementation class based on JSON attribute name, eg. for JSON object:
{
...
cat: {...}
...
}
i would just wite:
setImpl("cat", Cat.class);
I know it's possible in Jackson to embed class information inside JSON, but I don't want to complicate the JSON format I use. I want to decide what class to use just by setting default implementation class, or by the attribute name ('cat') - like in XStream library, where you write:
xStream.alias("cat", Cat.class);
Is there a way to do so, especially in one line, or does it require some more code?
There are multiple ways; before version 1.8, simplest way is probably to do:
#JsonDeserialize(as=Cat.class)
public abstract class AbstractAnimal { ... }
as to deciding based on attribute, that is best done using #JsonTypeInfo, which does automatic embeddeding (when writing) and use of type information.
There are multiple kinds of type info (class name, logical type name), as well as inclusion mechanisms (as-included-property, as-wrapper-array, as-wrapper-object). This page: https://github.com/FasterXML/jackson-docs/wiki/JacksonPolymorphicDeserialization explains some of the concepts.
A full fledged answer with a very clear example can be found here: https://stackoverflow.com/a/30386694/584947
Jackson refers to this as Polymorphic Deserialization.
It definitely helped me with my issue. I had an abstract class that I was saving in a database and needed to unmarshal it to a concrete instance of a class (understandably).
It will show you how to properly annotate the parent abstract class and how to teach jackson how to pick among the available sub-class candidates at run-time when unmarshaling.
If you want to pollute neither your JSON with extra fields nor your classes with annotation, you can write a very simple module and deserializer that uses the default subclass you want. It is more than one line due to some boilerplate code, but it is still relatively simple.
class AnimalDeserializer extends StdDeserializer<Animal> {
public AnimalDeserializer() {
super(Animal.class);
}
public Animal deserialize(JsonParser jsonParser, DeserializationContext context) throws IOException {
return jsonParser.readValueAs(Cat.class);
}
}
class AnimalModule extends SimpleModule {
{
addDeserializer(Animal.class, new AnimalDeserializer());
}
}
Then register this module for the ObjectMapper and that's it (Zoo is the container class that has an Animal field).
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.registerModule(new AnimalModule());
return objectMapper.readValue(json, Zoo.class);
The problem can be solved with the annotation #JsonDeserialize on the abstract class.
Refers to Jackson Exceptions Problems and Solutions for more info