VM JAXB property 'dateOfHire' is of type 'org.joda.time.LocalDate' but is not annotated with #XmlJavaTypeAdapter - isis

On JAXB I have a LocalDate property
#Property(editing = Editing.ENABLED)
#Getter #Setter
private LocalDate dateOfHire;
On my other entity I have added #XmlJavaTypeAdapter(PersistentEntityAdapter.class) they work fine, but LocalDate is org.joda.time.LocalDate so I can't add annotation into it. When I run my VM throw exception:
JAXB view model 'domainapp.modules.employment.dom.employee.EmployeeVM' property 'dateOfHire' is of type 'org.joda.time.LocalDate' but is not annotated with #XmlJavaTypeAdapter. The field/method must be annotated with #XmlJavaTypeAdapter(org.apache.isis.schema.utils.jaxbadapters.XxxAdapter.ForJaxb.class) or equivalent.
Please Help!!!

Annotate the field instead ... as per our docs

Related

#Cacheable annotation cannot work as expected when deserialize beans with LocalDateTime type property

I found that the annotation #Cacheable cannot work when the method returns a Java Bean type, this is the complete description:
I annotated #Cacheable on a method to use spring cache:
#Cacheable(cacheNames="userCache", key="#userId")
public User getUser(long userId){
return userRepository.getUserById(userId);
}
And the User class like this:
public class User{
Long userId;
String username;
#JsonSerialize(using = LocalDateTimeSerializer.class)
#JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime birthDateTime;
}
As you can see, I annotated the relating Jackson annotations to make Jackson deserialization for LocalDateTime types work, and this is the related dependency in pom.xml:
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jsr310</artifactId>
<version>2.12.5</version>
</dependency>
After that, I call the #Cacheable method getUser like this:
User user = userCache.getUser(1L);
and there throws an exception:
org.redisson.client.RedisException: Unexpected exception while processing command
at org.redisson.command.CommandAsyncService.convertException(CommandAsyncService.java:326)
at org.redisson.command.CommandAsyncService.get(CommandAsyncService.java:123)
at org.redisson.RedissonObject.get(RedissonObject.java:82)
...blabla
Caused by: com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Java 8 date/time type java.time.LocalDateTime not supported by default: add Module "com.fasterxml.jackson.datatype:jackson-datatype-jsr310" to enable handling at [Source: (io.netty.buffer.ByteBufInputStream); line: 1, column: 101] (through reference chain: com.stackoverflow.domain.User["birthDateTime"]) at com.fasterxml.jackson.databind.exc.InvalidDefinitionException.from(InvalidDefinitionException.java:67)
at com.fasterxml.jackson.databind.DeserializationContext.reportBadDefinition(DeserializationContext.java:1764)
at com.fasterxml.jackson.databind.deser.impl.UnsupportedTypeDeserializer.deserialize(UnsupportedTypeDeserializer.java:36)
at com.fasterxml.jackson.databind.deser.impl.MethodProperty.deserializeAndSet(MethodProperty.java:129)
3.Before I use the #Cacheable, there is no problem if I get the User from database straightly. But when I begin to use #Cacheable, it always throws the exception above, no matter if I configured those Jackson deserialization for LocalDateTime. Is #Cacheable cannot work well with Java Bean with LocalDateTime property, or just my configuration of Jackson is wrong?
I had the same problem. Spring Cache doesn't use the implicit ObjectMapper used by other Spring components.
Include the module, you already did that.
Create a configuration which will override the default Spring Cache Configuration:
#Configuration
#EnableCaching
public class CacheConfiguration {
#Bean
public RedisSerializationContext.SerializationPair<Object> serializationPair() {
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.registerModule(new JavaTimeModule())
.activateDefaultTyping(
objectMapper.getPolymorphicTypeValidator(),
ObjectMapper.DefaultTyping.EVERYTHING,
JsonTypeInfo.As.PROPERTY
);
return RedisSerializationContext.SerializationPair.fromSerializer(new GenericJackson2JsonRedisSerializer(objectMapper));
}
#Bean
public RedisCacheConfiguration redisCacheConfiguration(
#Value("${cache.default-ttl-in-seconds}") Integer ttl,
RedisSerializationContext.SerializationPair<Object> serializationPair
) {
return RedisCacheConfiguration.defaultCacheConfig()
.disableCachingNullValues()
.entryTtl(Duration.ofSeconds(ttl))
.serializeValuesWith(serializationPair);
}
}

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.

Kotlin classes not identified as Flink valid POJO's

I am writing a Flink application in Kotlin and data classes (as well as other Kotlin classes) are not identified as valid POJO types.
The Flink documentation states that a data type is recognized as a POJO type (and allows "by-name" field referencing) if the following conditions are fulfilled:
The class is public and standalone
The class has a public no-argument constructor
All non-static, non-transient fields in the class are either public (and non-final) or have public getter and setter methods that follow Java beans naming conventions.
I receive the following when implementing a Kotlin data class, which should meet the aforementioned conditions to be recognized as a POJO:
[main] INFO org.apache.flink.api.java.typeutils.TypeExtractor -
Class class <Class> cannot be used as a POJO type because not all
fields are valid POJO fields, and must be processed as GenericType.
Please read the Flink documentation on "Data Types & Serialization"
for details of the effect on performance.
Investigating further, I reviewed Flink's TypeExtractor.isValidPojoField method # https://github.com/apache/flink/blob/master/flink-core/src/main/java/org/apache/flink/api/java/typeutils/TypeExtractor.java
In a separate project, I applied the field checks with java.lang.reflect.Modifier on a simple Kotlin data class in attempt to narrow down the issue.
data class SomeDataClass(
val topic: String = "",
val message: String = ""
)
While Kotlin class fields have public visibility by default, Modifier.isPublic recognizes the fields as private. Additionally, Modifier.isFinal recognizes the fields as final.
val clazz = SomeDataClass::class.java
val fields = clazz.declaredFields
fields.forEach { it ->
println("field: $it")
println(it.genericType)
println("public? " + Modifier.isPublic(it.modifiers))
println("final? " + Modifier.isFinal(it.modifiers))
println("transient? " + Modifier.isTransient(it.modifiers))
println("static? " + Modifier.isStatic(it.modifiers))
}
>
field: private final java.lang.String SomeDataClass.topic
class java.lang.String
public? false
final? true
transient? false
static? false
However, public getter and setter methods are created for these fields, so this object should still meet the POJO criteria.
println(clazz.declaredMethods.toList())
>
[public boolean SomeDataClass.equals(java.lang.Object),
public java.lang.String SomeDataClass.toString(),
public int SomeDataClass.hashCode(),
**public final java.lang.String SomeDataClass.getMessage(),**
public final SomeDataClass SomeDataClass.copy(java.lang.String,java.lang.String),
**public final java.lang.String SomeDataClass.getTopic(),**
public final java.lang.String SomeDataClass.component1(),
public final java.lang.String SomeDataClass.component2(),
public static SomeDataClass SomeDataClass.copy$default(SomeDataClass,java.lang.String,java.lang.String,int,java.lang.Object)]
The getter and setter methods, however, are final, which leads me to believe this is the issue.
I am relatively new to JVM development, so any help would be greatly appreciated. I have reviewed the Flink Jira, Stack Overflow, and Flink mailing list and have not found a similar issue reported.
I see at least two POJO rules violation with provided data class.
1) The class has a public no-argument constructor
By default, Kotlin will not generate overloads to functions with default parameter values (https://kotlinlang.org/docs/reference/java-to-kotlin-interop.html#overloads-generation)
So your compiled class will have only one constructor with two-parameter constructor, and no-argument constructor will not be created. To force Kotlin compiler to generate multiple overloads one should use #JvmOverloads annotation. In your case it will be used on constructor so we also need to add constructor keyword:
data class SomeDataClass #JvmOverloads constructor
2) All non-static, non-transient fields in the class are either public (and non-final) or have public getter and setter methods that follow Java beans naming conventions.
Since you are using val keywords the generated fields will be final, and no setter will be generated for them. So you can change vals to vars and the fields will no longer be final and proper getters and setters will be generated too. (Or you could use another annotation to prevent generating getters and setters and expose a field as it is https://kotlinlang.org/docs/reference/java-to-kotlin-interop.html#instance-fields)
So final code should be like this:
data class SomeDataClass #JvmOverloads constructor(
var topic: String = "",
var message: String = ""
)
If you wish to use kotlin data classes without any modifications to match a Java POJO (i.e: no default/null values required and keep using val).
You can either:
provide a custom Kryo serializer to serialize it using Protobuf or Avro (or the tool and format of your choice).
use a Kotlin friendly type serializer that will serialize your data class similarly to a case class.

Lombok + Intellij: cannot resolve method of super class

I have a superclass
#Data
#AllArgsConstructor
#NoArgsConstructor
#Builder
public class ErrorResponse {
#JsonProperty
private String message;
}
And I have a child one
#Data
#NoArgsConstructor
#AllArgsConstructor
#Builder(builderMethodName = "_builder") // add custom builder name to avoid compilation issue 'return type is not compatible...'
#EqualsAndHashCode(callSuper=true)
public class AskQuestionErrorResponse extends ErrorResponse {
#JsonProperty
private String status;
#Builder(builderMethodName = "_builder") // add custom builder name to avoid compilation issue 'return type is not compatible...'
private AskQuestionErrorResponse(String status, String message){
super(message);
this.status = status;
}
}
When I use a builder to create an object like this
AskQuestionErrorResponse._builder()
.status(1)
.message("my message here").build()
Intellij shows me message in red and there is an issue cannot resolve method 'message(java.lang.String)' Anyway project compiles and runs even with this error.
I've already enabled annotations precessing.
If I comment field from superclass like this
AskQuestionErrorResponse._builder()
.status(ex.getStatus().getValue()
//.message(ex.getMessage()
).build()
It works. It seems that it does not see superclass members. I've also tried maven clean and install, rebuild project.
UPDATE
Lombok plugin is installed
Annotation Processors are enabled in Preferences and in Default preferences
I found it. If you take a look to my class you'll see two #Builder annotations. I removed first one and magic happens. Now my class looks like this and there is no warning
#Data
#NoArgsConstructor
#AllArgsConstructor
#EqualsAndHashCode(callSuper=true)
public class AskQuestionErrorResponse extends ErrorResponse {
#JsonProperty
private String status;
#Builder(builderMethodName = "_builder") // add custom builder name to avoid compilation issue 'return type is not compatible...'
public AskQuestionErrorResponse(String status, String message){
super(message);
this.status = status;
}
}
Hope it helps :)
You need to install the Intellij Lombok plugin so that it can understand the annotations before the compilation to byte code.
https://projectlombok.org/setup/intellij

Register JodaModule in Jax-RS Application

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.