How do I programmatically configure ObjectMapper in Java/Jackson to instantiate Java beans? - jackson

I have a number of Java bean interfaces like this:
public interface Dog
{
String getName();
void setName( final String value );
}
I also auto-generate bean implementations like this:
public final class DogImpl implements Dog
{
public String getName()
{
return m_name;
}
public void setName( final String value )
{
m_value = value;
}
private volatile String m_value;
}
ObjectMapper works perfectly except when I start nesting these beans like this:
public interface Dog
{
String getName();
void setName( final String value );
Dog getParent();
void setParent( final Dog value );
}
I get this error:
abstract types either need to be mapped to concrete types, have custom deserializer, or contain additional type information
It's complaining because the bean definition is an interface and not the concrete type. My question is if there is a way for me to define the mapping of interface types to concrete types for the ObjectMapper via a module or something?
Specifically, I can get a Map< Class< ? >, Class< ? > > of api type to implementation concrete type, but have no idea how to "give this" to the ObjectMapper so it understands how to look up the concrete types from the api types so it can instantiate them. How do I accomplish this?

This can be done using a SimpleAbstractTypeResolver.
This link shows you how to add the mappings to the resolver: Jackson - How to specify a single implementation for interface-referenced deserialization?
And this is how you add the resolver to an ObjectMapper:
final SimpleAbstractTypeResolver resolver = new SimpleAbstractTypeResolver();
for ( final Class< ? > api : apis )
{
resolver.addMapping( api, getConcreteImpl( api ) );
}
final SimpleModule module = new SimpleModule();
module.setAbstractTypes( resolver );
mapper.registerModule( module );

Related

Golang embedding interfaces in struct with private access

I want to replicate the following Java code in Golang in the most idiomatic way possible:
public class Handler {
private Storage storage;
private Mapper mapper;
public Handler(Storage storage, Mapper mapper) {
this.storage = storage;
this.mapper = mapper;
}
public void handleKey(String k) {
storage.put(k, mapper.map(k));
}
}
interface Storage {
public void put(String k, String v);
public String get(String k);
}
#FunctionalInterface
interface Mapper {
public String map(String a);
}
private static class InMemoryStorage implements Storage {
private Map<String, String> table;
public InMemoryStorage() {
table = new HashMap<>();
}
public void put(String k, String v) {
table.put(k, v);
}
public String get(String k) {
return table.get(k);
}
}
Handler class only exposes the method handleKey. The behaviour of this class is parametrized by passing different concrete Storage and Mapper implementations.
After reading Effective Go - Embedding, I thought this would be a good use of embedding interfaces intro structs. But I can't figure out how to avoid exposing the embedded interfaces' methods to Handler users. I can do something like
type Handler struct {
store Storage
mapper Mapper
}
func (h Handler) Handle(k string) {
h.store.Put(k, h.mapper.Map(k))
}
type Storage interface {
Put(k string, v string)
Get(k string) string
}
type Mapper interface {
Map(k string) string
}
type inMemoryStorage {
table map[string]string
}
func NewInMemoryStorage() Storage {
return &inMemoryStore{table: make(map[string]string)}
}
but then I cannot pass concrete implementations to the Handler (creating struct literal) because store and mapper are unexported. And I do not want to create factory methods for each possible combination... Any suggestions?
Those are not embedded; embedding has a specific meaning in Go, as outlined in the spec, and as explained in the Effective Go section you linked to. It refers to unnamed fields, whose fields and methods are accessible implicitly from their containing type. Your fields are named, not embedded.
That said, your two struct fields, store and mapper, are not exported, so they will not be exposed to any user outside the package in which Handler is defined; you seem to already have your desired behavior in that regard.
I'm not sure what you mean when you say you would have to "create factory methods for each possible combination" - I don't see any reason that would be necessary. You need only one factory method:
func NewHandler(s Storage, m Mapper) Handler {
return Handler{store: s, mapper: m}
}
Which could be used with any combination of implementations of Storage and Mapper by passing appropriate values to the function.

Accessing Java bean properties from Kotlin

I have wsimport-ed Java classes with standard bean conventions:
public class Request {
protected String vin;
public String getVin() {
return vin;
}
public void setVin(String value) {
this.vin = value;
}
}
I expected to use this class in Kotlin using nice property syntax:
override fun search(request: Request): Response {
log.info("search(vin={})", request.vin);
...
but this code does not compile:
Error:(59, 64) Kotlin: Cannot access 'vin': it is 'protected/*protected and package*/' in 'SmvSearchRequest'
request.getVin() works, of course, but that doesn't look better than Java. Is there some way to treat those classes as property holders?
This was missing pre-M13, it is now fixed in M13, see Youtrack

Morphia Interface for List of enum does not work (unmarshalling)

I have the following interface
#JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, include = JsonTypeInfo.As.PROPERTY, property = "className")
public interface InfoChartInformation {
public String name();
}
And the following implementation (enum):
public class InfoChartSummary {
public static enum Immobilien implements InfoChartInformation {
CITY, CONSTRUCTION_DATE;
}
public static enum Cars implements InfoChartInformation {
POWER, MILEAGE;
}
}
Then I use all of It in the following entity:
#Entity(noClassnameStored = true)
#Converters(InfoChartInformationMorphiaConverter.class)
public class TestEntity{
#Id
public ObjectId id;
#Embedded
public List<InfoChartInformation> order;
}
Jackson, in order to detect the type on the unmarshalling time, will add to every enum on the list the className.
I thought morphia would do the same, but there's no field className in the List of enum and the unmarshalling cannot be done correctly: java.lang.RuntimeException: java.lang.RuntimeException: java.lang.RuntimeException: java.lang.ClassCastException: java.lang.String cannot be cast to com.mongodb
.DBObject
I guess the correct behavior should be to save all the enum route (package+name), not only the enum name. At least in that way the unmarshalling could be performed. There's a way morphia supports that by default or I need to create my own converter (similar to this) ?
I tried creating a Custom Converter:
public class InfoChartInformationMorphiaConverter extends TypeConverter{
public InfoChartInformationMorphiaConverter() {
super(InfoChartInformation.class);
}
#Override
public Object decode(Class targetClass, Object fromDBObject, MappedField optionalExtraInfo) {
if (fromDBObject == null) {
return null;
}
String clazz = fromDBObject.toString().substring(0, fromDBObject.toString().lastIndexOf("."));
String value = fromDBObject.toString().substring(fromDBObject.toString().lastIndexOf(".") + 1);
try {
return Enum.valueOf((Class)Class.forName(clazz), value);
} catch (ClassNotFoundException e) {
return null;
}
}
#Override
public Object encode(final Object value, final MappedField optionalExtraInfo) {
return value.getClass().getName() + "." + ((InfoChartInformation) value).name();
}
}
Then, I added the converter information to morphia morphia.getMapper().getConverters().addConverter(new InfoChartInformationMorphiaConverter());.
However, when serializing (or marshalling) the object to save it into the database, the custom converter is ignored and the Enum is saved using the default Morphia converter (only the enum name).
If I use in the TestEntity class only an attribute InfoChartInformation; instead of the List<>InfoChartInformation>, my customer converter will work. However I need support for List
Use:
public class InfoChartInformationMorphiaConverter extends TypeConverter implements SimpleValueConverter
It is a marker interface required to make your Convertor work.

Hibernate Validator and Jackson: Using the #JsonProperty value as the ConstraintViolation PropertyPath?

Say I have a simple POJO like below annotated with Jackson 2.1 and Hibernate Validator 4.3.1 annotations:
final public class Person {
#JsonProperty("nm")
#NotNull
final public String name;
public Person(String name) {
this.name = name;
}
}
And I send JSON like such to a web service:
{"name": null}
Hibernate when it reports the ConstraintViolation uses the class member identifier "name" instead of the JsonProperty annotation value. Does anyone know if it is possible to make the Hibernate Validator look at the annotation of the class and use that value instead?
Unfortunately there is no easy way to do it. But here are some insights that can help you:
Parsing constraint violations
From the ConstraintViolationException, you can get a set of ConstraintViolation, that exposes the constraint violation context:
ConstraintViolation#getLeafBean(): If it is a bean constraint, this method returns the bean instance in which the constraint is applied to.
ConstraintViolation#getPropertyPath(): Returns the path to the invalid property.
From the property path, you can get the leaf node:
Path propertyPath = constraintViolation.getPropertyPath();
Optional<Path.Node> leafNodeOptional =
StreamSupport.stream(propertyPath.spliterator(), false).reduce((a, b) -> b);
Then check if the type of the node is PROPERTY and get its name:
String nodeName = null;
if (leafNodeOptional.isPresent()) {
Path.Node leafNode = leafNodeOptional.get();
if (ElementKind.PROPERTY == leafNode.getKind()) {
nodeName = leafNode.getName();
}
}
Introspecting a class with Jackson
To get the available JSON properties from the leaf bean class, you can introspect it with Jackson (see this answer and this answer for further details):
Class<?> beanClass = constraintViolation.getLeafBean().getClass();
JavaType javaType = mapper.getTypeFactory().constructType(beanClass);
BeanDescription introspection = mapper.getSerializationConfig().introspect(javaType);
List<BeanPropertyDefinition> properties = introspection.findProperties();
Then filter the properties by comparing the leaf node name with the Field name from the BeanPropertyDefinition:
Optional<String> jsonProperty = properties.stream()
.filter(property -> nodeName.equals(property.getField().getName()))
.map(BeanPropertyDefinition::getName)
.findFirst();
Using JAX-RS?
With JAX-RS (if you are using it), you can define an ExceptionMapper to handle ConstraintViolationExceptions:
#Provider
public class ConstraintViolationExceptionMapper
implements ExceptionMapper<ConstraintViolationException> {
#Override
public Response toResponse(ConstraintViolationException exception) {
...
}
}
To use the ObjectMapper in your ExceptionMapper, you could provide a ContextResolver<T> for it:
#Provider
public class ObjectMapperContextResolver implements ContextResolver<ObjectMapper> {
private final ObjectMapper mapper;
public ObjectMapperContextResolver() {
mapper = createObjectMapper();
}
#Override
public ObjectMapper getContext(Class<?> type) {
return mapper;
}
private ObjectMapper createObjectMapper() {
ObjectMapper mapper = new ObjectMapper();
mapper.configure(SerializationFeature.INDENT_OUTPUT, true);
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
return mapper;
}
}
Inject the Providers interface in your ExceptionMapper:
#Context
private Providers providers;
Lookup for your ContextResolver<T> and then get the ObjectMapper instance:
ContextResolver<ObjectMapper> resolver =
providers.getContextResolver(ObjectMapper.class, MediaType.WILDCARD_TYPE);
ObjectMapper mapper = resolver.getContext(ObjectMapper.class);
If you are interested in getting #XxxParam names, refer to this answer.
No, that's not possible. Hibernate Validator 5 (Bean Validation 1.1) has the notion of ParameterNameProviders which return the names to reported in case method parameter constraints are violated but there is nothing comparable for property constraints.
I have raised this issue as I am using problem-spring-web module to do the validation, and that doesn't support bean definition names out of box as hibernate. so I have came up with the below logic to override the createViolation of ConstraintViolationAdviceTrait and fetch the JSONProperty field name for the field and create violations again.
public class CustomBeanValidationAdviceTrait implements ValidationAdviceTrait {
private final ObjectMapper objectMapper;
public CustomBeanValidationAdviceTrait(ObjectMapper objectMapper) {
this.objectMapper = objectMapper;
}
#Override
public Violation createViolation(ConstraintViolation violation) {
String propertyName = getPropertyName(violation.getRootBeanClass(), violation.getPropertyPath().toString());
return new Violation(this.formatFieldName(propertyName), violation.getMessage());
}
private String getPropertyName(Class clazz, String defaultName) {
JavaType type = objectMapper.constructType(clazz);
BeanDescription desc = objectMapper.getSerializationConfig().introspect(type);
return desc.findProperties()
.stream()
.filter(prop -> prop.getInternalName().equals(defaultName))
.map(BeanPropertyDefinition::getName)
.findFirst()
.orElse(defaultName);
}

Jackson mixin selection and inheritance

I have a problem with Jackson mixin and inheritance. I have two target classes, a parent and a child. For those two target classes I have defined two MixIn classes (interfaces) with no inheritance relationship with each other. I also tested with one MixIn interface extending the other but there was no difference in the outcome. When Jackson serializes the parent class it uses the correctly defined mixin for the serialization config and everything works well. However when Jackson serializes the child class it will use the parent class mixin definitions for serializing properties that exist in both the parent and the child class. Then it uses the child class mixin definitions for serializing the properties defined in the child class but not in the parent class. Now this probably has something to do with comparing the base classes or implementing interfaces in Jackson.
Now the question is that is there any way that I could instruct Jackson to use only the mixin definitions for the child class when serializing objects of the child class? And yes I would like to keep both the the mixin definitions in place for two separate use cases so just removing the parent class mixin mapping is not gonna solve my issue.
Example code and expected and actual output JSONs below.
Environment:
Jackson version 2.1.4
Tomcat version 7.0.34.0
Target classes and interfaces they implement:
public interface TestI {
public String getName();
}
public interface TestExtendI extends TestI {
public Integer getAge();
}
public class Test implements TestI {
String name;
public Test(String name) {
this.name = name;
}
#Override
public String getName() {
return name;
}
}
public class TestExtend extends Test implements TestExtendI {
private Integer age;
public TestExtend(String name) {
super(name);
}
public TestExtend(String name, Integer age) {
super(name);
this.age = age;
}
#Override
public Integer getAge() {
return age;
}
}
Mixins definitions
public interface TestMixIn {
#JsonProperty("base-name")
public String getName();
}
public interface TestExtendMixIn {
#JsonProperty("ext-name")
public String getName();
#JsonProperty("ext-age")
public Integer getAge();
}
If both mixins are added to the mapper the output JSON is:
{
"base-name": "5", // from parent class mixin definition
"ext-age": 50 // from child class mixin defition
}
With mixin for TestI.class commented everything works as expected and the output JSON is (this is what I would like to achieve):
{
"ext-name": "5", // from child class mixin defition
"ext-age": 50 // from child class mixin defition
}
Object mapper configuration
#Provider
#Produces(MediaType.APPLICATION_JSON)
public class JacksonObjectMapper implements ContextResolver<ObjectMapper> {
private ObjectMapper mapper;
public JacksonObjectMapper() {
mapper = new ObjectMapper();
mapper.addMixInAnnotations(TestI.class, TestMixIn.class);
mapper.addMixInAnnotations(TestExtendI.class, TestExtendMixIn.class);
}
public ObjectMapper getContext(Class<?> type) {
return this.mapper;
}
}
REST api for handling the request/response
#Path("api/test/{id}")
public class TestRestApi {
#GET
#Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
public TestI getTest(#PathParam("id") String id) {
TestI ret = new TestExtend(id, 50);
return ret;
}
}
Solution
As described by pgelinas in the first response the solution to this problem is to define the methods that should be handled by the 'child' mixin again in the child interface. For the example code above that would mean changes to the TestExtendI interface:
public interface TestExtendI extends TestI {
public Integer getAge();
// override the method from the parent interface here
#Override
public String getName();
}
This will solve the issue and doesn't add too much boilerplate code to the solution. Moreover it will not change the interface contracts since the child interface already extends the parent interface.
This is a tricky one; the answer to your specific question is no, you cannot tell a child class to not use the Mixin applied to a parent class.
However, a simple solution to your problem here is to re-declare the getName() method in the TestExtendI interface. I believe MixIn annotation resolution doesn't follow the usual parent-child override (as is the case with normal annotations), but will instead prefer the MixIn that is applied to the class that declares the method. This might be a bug in Jackson or a design choice, you can always fill an issue on github.