Reputation: 13521
Using Spring 3 and Jackson 1.7.6, I can serialize implementations of an abstract class and output the fully-qualified name of the class as a property called @class
. This works fine when my Spring controllers return a single instance from a controller annotated with @ResponseBody
.
When returning a Collection
of the above types the resulting JSON changes according to which type is being serialized (fields from each subclass are present), but it does not include the @class
property, which our client code needs.
How can I get this type hint into the serialized JSON when returning a collection?
//Returns complete with @class=com.package.blah
@RequestMapping("/json/getProduct.json")
public @ResponseBody Product getProduct(Integer id)
{
return service.getProduct(id);
}
//Does not include @class
@RequestMapping("/json/getProducts.json")
public @ResponseBody List<Product> getProducts()
{
return service.getProducts();
}
Upvotes: 4
Views: 4680
Reputation: 75
Object mapper bean can enable default typing:
ObjectMapper mapper = new ObjectMapper()
mapper.enableDefaultTyping(DefaultTyping.NON_FINAL, As.PROPERTY);
This will give the json output as following:
[
"java.util.ArrayList",
[
{
"@class": "com.xyz.Product",
"name": "myName"
}
]
]
Upvotes: 0
Reputation: 1
I had the problem withjava.util.Map
, so I did something like:
public interface MyMap extends Map<Long, Product> {}
and
public class MyHashMap extends HashMap<Long, Product> implements MyMap {}
Upvotes: 0
Reputation: 116620
You can use @JsonTypeInfo with POJOs, Collections and Maps, but note that the declared value type of Collections and Maps must be one that has (or inherits) @JsonTypeInfo annotation (when using per-class @JsonTypeInfo annotation). This would not work, for example, if you have type like "Collection" -- in this case, Deejay's answer is correct, as you can force inclusion with "default typing" option.
But things should also work if you have a Collection property to serialize/deserialize, i.e.:
public class Bean {
@JsonTypeInfo(....)
public Collection<Object> listOfObjects; // does work because it's per-property annotation!
// ... also, applies to value type and not Collection type itself
}
since that will override any @JsonTypeInfo annotations value type might otherwise have
Upvotes: 2
Reputation: 13521
In order to do this you will need to configure ObjectMapper. This is not straightforward via Spring, as rather than settable properties, ObjectMapper has invokable methods that set its state (and then it stores this as a bitmask).
If you are using <mvc:annotation-driven />
you will need to replace it with the equivalent markup, which can be found in the Spring JavaDocs.
Extend ObjectMapper:
public class ConfigurableObjectMapper extends ObjectMapper
{
public ConfigurableObjectMapper()
{
this.enableDefaultTypingAsProperty(DefaultTyping.JAVA_LANG_OBJECT, JsonTypeInfo.Id.CLASS.getDefaultPropertyName());
}
}
Then tell Spring to use an instance of this class instead of the default implementation.
<bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping">
<property name="order" value="0" />
</bean>
<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
<property name="webBindingInitializer">
<bean class="org.springframework.web.bind.support.ConfigurableWebBindingInitializer">
<property name="validator" ref="validator" />
</bean>
</property>
<property name="messageConverters">
<list>
<bean class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter">
<property name="objectMapper">
<bean class="com.blitzgamesstudios.web.common.json.ConfigurableObjectMapper" />
</property>
</bean>
<bean class="org.springframework.http.converter.ByteArrayHttpMessageConverter" />
<bean class="org.springframework.http.converter.StringHttpMessageConverter" />
<bean class="org.springframework.http.converter.FormHttpMessageConverter" />
<bean class="org.springframework.http.converter.xml.SourceHttpMessageConverter" />
</list>
</property>
</bean>
<bean id="validator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean" />
Upvotes: 2