Register JodaModule in Jax-RS Application - jackson

I'm writing a Jax-RS application using Jersey, and Jackson2 under the hood to facilitate JSON i/o. The service itself works fine, but I'd like to improve it by having the Jackson mapper automagically serialize/deserialize date and date-times to JodaTime objects.
I'm following the documentation here and have added the relevant jars, but I'm lost on this instruction:
Registering module
To use Joda datatypes with Jackson, you will first need to register the module first (same as with all Jackson datatype modules):
ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(new JodaModule());
I've tried to do this in the custom class that extends jax.ws.rs.core.Application, but I'm not at all confident in that solution. I'm currently getting this error:
Can not instantiate value of type [simple type, class org.joda.time.DateTime] from String value ('2014-10-22'); no single-String constructor/factory method
at [Source: org.glassfish.jersey.message.internal.ReaderInterceptorExecutor$UnCloseableInputStream#3471b6d5; line: 7, column: 25]
Other than the general impression that this module registration needs to happen at application (servlet?) startup, I have no idea what to do with this information. Do I need to annotate a custom class with something in particular to have it picked up ? Should I be extending some class ?
The examples I find on StackOverflow usually stick it in main() and call the mapper directly, but I'm relying on Jackson Databinding so the examples aren't relevant. Any direction is appreciated.

You'll basically want to create/configure/return the ObjectMapper in a ContextResolver. Something like
#Provider
public class ObjectMapperContextResolver implements ContextResolver<ObjectMapper> {
final ObjectMapper mapper = new ObjectMapper();
public ObjectMapperContextResolver() {
mapper.registerModule(new JodaModule());
}
#Override
public ObjectMapper getContext(Class<?> type) {
return mapper;
}
}
If you are using package scanning to discover your resources, then the #Provider annotation should allow this class to be discovered and registered also.
Basically what happens, is the the MessageBodyReader and MessageBodyWriter provided by Jackson, used for unmarshalling and marshalling, respectively, will call the getContext method in the ContextResolver, to determine the ObjectMapper to use. The reader/writer will pass in the class (in a reader it will be the type expected in a method param, in a writer it will be the type returned as-a/in-a response), meaning we are allowed to use differently configured ObjectMapper for different classes, as seen here. In the above solution, it is used for all classes.

Related

When I subclass a class using ByteBuddy in certain situations I get IllegalAccessErrors. Why?

(I am a new ByteBuddy user. I'm using ByteBuddy version 1.10.8 and JDK 11 without the module path or any other part of the module system.)
I have a nested class declared like this:
public static class Frob {
protected Frob() {
super();
}
public String sayHello() {
return "Hello!";
}
}
(Its containing class is foo.bar.TestExplorations.)
When I create a dynamic subclass of Frob named foo.bar.Crap like the following, everything works OK as I would expect:
final String className = "foo.bar.Crap";
final DynamicType.Unloaded<?> dynamicTypeUnloaded = new ByteBuddy()
.subclass(Frob.class)
.name(className)
.make();
final Class<?> mySubclass = dynamicTypeUnloaded
.load(this.getClass().getClassLoader(), ClassLoadingStrategy.Default.WRAPPER)
.getLoaded();
assertNotNull(mySubclass);
assertEquals(className, mySubclass.getName());
final Object frobSubclass = mySubclass.newInstance();
assertTrue(frobSubclass instanceof Frob);
But if I change Frob's constructor so that it is package private, I get the following error from the final assertion:
java.lang.IllegalAccessError: class foo.bar.Crap tried to access method 'void foo.bar.TestExplorations$Frob.<init>()' (foo.bar.Crap is in unnamed module of loader net.bytebuddy.dynamic.loading.ByteArrayClassLoader #5e3d57c7; foo.bar.TestExplorations$Frob is in unnamed module of loader 'app')
For some reason, Crap's constructor cannot call super(), even though Crap and Frob are in the same package, and Frob() is defined as package-private.
I have a sense the JDK module system is to blame here, even though I am deliberately (very, very deliberately) not using it. I know the module system does not like split packages, which is what it looks like to me is going on here. Is there a constructor strategy or other mechanism to work around this problem?
In Java, a package is only equal to another package if it has the same name and is loaded by the same class loader (the same as it is with classes). If you are using the WRAPPER strategy, you cannot access package-private members of any super class. Byte Buddy does not forbid the generation as it would be legal to do in javac but you would need to use the INJECTION strategy to do what you want to make sure that classes are loaded by the same class loader. Mind that it uses internal API, therefore, from Java 9, you'd rather use a ForLookup class loading strategy.

Why jackson is not serializing this?

#Data
public class IdentificacaoBiometricaDto {
private Integer cdIdentifBiom;
private String nrMatricula;
private String deImpressaoDigital;
private Integer cdFilialAtualizacao;
}
I am using retrofit 2.6.1, jackson 2.9.9 and lombok 1.8.10.
The exception is:
Caused by: com.fasterxml.jackson.databind.exc.InvalidDefinitionException: No serializer found for class br.com.clamed.modelo.loja.dto.central.IdentificacaoBiometricaDto and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS)
at com.fasterxml.jackson.databind.exc.InvalidDefinitionException.from(InvalidDefinitionException.java:77)
at com.fasterxml.jackson.databind.SerializerProvider.reportBadDefinition(SerializerProvider.java:1191)
at com.fasterxml.jackson.databind.DatabindContext.reportBadDefinition(DatabindContext.java:313)
at com.fasterxml.jackson.databind.ser.impl.UnknownSerializer.failForEmpty(UnknownSerializer.java:71)
at com.fasterxml.jackson.databind.ser.impl.UnknownSerializer.serialize(UnknownSerializer.java:33)
at com.fasterxml.jackson.databind.ser.DefaultSerializerProvider._serialize(DefaultSerializerProvider.java:480)
at com.fasterxml.jackson.databind.ser.DefaultSerializerProvider.serializeValue(DefaultSerializerProvider.java:400)
at com.fasterxml.jackson.databind.ObjectWriter$Prefetch.serialize(ObjectWriter.java:1392)
at com.fasterxml.jackson.databind.ObjectWriter._configAndWriteValue(ObjectWriter.java:1120)
at com.fasterxml.jackson.databind.ObjectWriter.writeValueAsBytes(ObjectWriter.java:1017)
at retrofit2.converter.jackson.JacksonRequestBodyConverter.convert(JacksonRequestBodyConverter.java:34)
at retrofit2.converter.jackson.JacksonRequestBodyConverter.convert(JacksonRequestBodyConverter.java:24)
at retrofit2.ParameterHandler$Body.apply(ParameterHandler.java:355)
... 14 more
The object mapper:
return new ObjectMapper().registerModule(new ParameterNamesModule())
.registerModule(new Jdk8Module())
.registerModule(new JavaTimeModule())
.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
I am setting all fields, when passing it to a request body, retrofit fails because jackson could not serialize the object.
Retrofit call:
#POST("/usuario/v1.0/cadastraBiometria")
Call<IdentificacaoBiometricaDto> cadastraBiometria(#Body IdentificacaoBiometricaDto identificacaoBiometricaDto);
Rest service:
#RestController
#RequestMapping("/usuario")
public class UsuarioController {
#PostMapping(value = "/v1.0/cadastraBiometria")
public ResponseEntity<IdentificacaoBiometricaDto> cadastraBiometria(#RequestBody IdentificacaoBiometricaDto identificacaoBiometricaDto) {
}
}
Update:
If I change the retrofit converter to Gson it works;
If I serialize it using Jackson directly, it works;
Removing lombok makes no difference;
Found the problem. The biometric reader library was causing this. For some reason it's incompatible with openjdk-11 and is causing all sort of unrelated problems.
Yes, very weird. But the lib is very poorly done.

How to provide a custom MessageBodyWriter for Strings in CXF

I have registered a custom MessageBodyWriter<Object> implementation in my JAX-RS application. This writer can convert various types, including strings.
The custom converter is successfully used for other types, but for strings, CXF does not consider it: It does not even call isWriteable. (This was different in CXF 2.x, so there seems to have been a regression in CXF 3.x.)
Stepping through the CXF 3.1.11 code, I see that in the ProviderFactory.messageWriters list has two entries (StringTextProvider, JAXBElementTypedProvider) before my custom provider. The first one wants to convert strings, and being first in the list, it is preferred by CXF.
How can I change this to make my provider the preferred provider for strings? E.g. is it possible to drop the StringTextProvider? Or is it possible to reorder the list so that my provider comes first?
I found out that subclassing StringTextProvider and registering that class works:
#Provider
#Produces(MediaType.APPLICATION_JSON)
public class CustomeStringProvider extends StringTextProvider {
#Override
public void writeTo(String object, Class<?> type, Type genType, Annotation[] annotations, MediaType mediaType,
MultivaluedMap<String, Object> httpHeaders, OutputStream outputStream) throws IOException {
// ...
}
}
I got the idea for this approach from looking at the implementation of ProviderFactory.MessageBodyWriterComparator, which checks class hierarchies for ordering converters.

How do I create hypermedia links in custom serializer with Spring Data Rest

I have a abstract class and two implementations:
public abstract class Attribute {
// some properties
}
public class CustomAttribute extends Attribute{
private String property1;
}
public class DefaultAttribute extends Attribute{
private String property2;
}
There's another class, which includes these attributes:
public class Step{
private List<Attribute> attributes;
}
Now when Step gets serialized, the self link is missing. I need the self reference, since I want to update the attributes. According to the documentation, jackson needs a little help deciding which class to use. But that does not help, because I need to use both classes. So I build a custom serializer (and registered with a module) for Step and now I wonder how I can construct the link myself. I couldn't find anything in the Spring Data Rest docs regarding this. Since Spring Data Rest adds these links automatically, I think there might be a way to have the protocol/hostname/port information available in the JsonSerializer. How do I get the information in my custom serializer?
Ok, now I use the linkTo() function to get the hostname and port and I manually set the rest of the resource URL in my custom serializer.
final Link attributeLink = linkTo(CustomAttributeRepository.class)
.slash("/api")
.slash("customAttributes")
.slash(attribute.getIdentifier()).withSelfRel();
//#formatter:off
jsonGenerator.writeFieldName("_links");
jsonGenerator.writeStartObject();
jsonGenerator.writeFieldName("self");
jsonGenerator.writeStartObject();
jsonGenerator.writeStringField("href", attributeLink.getHref());
jsonGenerator.writeEndObject();
jsonGenerator.writeEndObject();
//#formatter:on

Dozer BeanFactory: How to implement it?

I have looked at the Dozer's FAQs and docs, including the SourceForge forum, but I didn't see any good tutorial or even a simple example on how to implement a custom BeanFactory.
Everyone says, "Just implement a BeanFactory". How exactly do you implement it?
I've Googled and all I see are just jars and sources of jars.
Here is one of my BeanFactories, I hope it helps to explain the common pattern:
public class LineBeanFactory implements BeanFactory {
#Override
public Object createBean(final Object source, final Class<?> sourceClass, final String targetBeanId) {
final LineDto dto = (LineDto) source;
return new Line(dto.getCode(), dto.getElectrified(), dto.getName());
}
}
And the corresponding XML mapping:
<mapping>
<class-a bean-factory="com.floyd.nav.web.ws.mapping.dozer.LineBeanFactory">com.floyd.nav.core.model.Line</class-a>
<class-b>com.floyd.nav.web.contract.dto.LineDto</class-b>
</mapping>
This way I declare that when a new instance of Line is needed then it should create it with my BeanFactory. Here is a unit test, that can explain it:
#Test
public void Line_is_created_with_three_arg_constructor_from_LineDto() {
final LineDto dto = createTransientLineDto();
final Line line = (Line) this.lineBeanFactory.createBean(dto, LineDto.class, null);
assertEquals(dto.getCode(), line.getCode());
assertEquals(dto.getElectrified(), line.isElectrified());
assertEquals(dto.getName(), line.getName());
}
So Object source is the source bean that is mapped, Class sourceClass is the class of the source bean (I'm ignoring it, 'cause it will always be a LineDto instance). String targetBeanId is the ID of the destination bean (too ignored).
A custom bean factory is a class that has a method that creates a bean. There are two "flavours"
a) static create method
SomeBean x = SomeBeanFactory.createSomeBean();
b) instance create method
SomeBeanFactory sbf = new SomeBeanFactory();
SomeBean x = sbf.createSomeBean();
You would create a bean factory if creating and setting up your bean requires some tricky logic, like for example initial value of certain properties depend on external configuration file. A bean factory class allows you to centralize "knowledge" about how to create such a tricky bean. Other classes just call create method without worying how to correctly create such bean.
Here is an actual implementation. Obviously it does not make a lot of sense, since Dozer would do the same without the BeanFactory, but instead of just returning an object, you could initialized it somehow differently.
public class ComponentBeanFactory implements BeanFactory {
#Override
public Object createBean(Object source, Class<?> sourceClass,
String targetBeanId) {
return new ComponentDto();
}
}
Why do you need a BeanFactory anyways? Maybe that would help understanding your question.