1

Problem

I am trying to have Jackson set any Empty String to null this is within a Spring-boot Application. We have added validation to our POJO to check to see that the value is between 1 and 255 IFF the value is being set.

@Size(min = 1, max = 255)
@Column(length = 255)
private String businessTitle;

The problem is that when a Empty String is passed to the validation it will fail with a javax.validation.ConstraintViolationException exception because it is checking the empty string.

I tried to setup DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT on the Jackson2ObjectMapperBuilder so it would set these empty strings as null and the validation would not fail. This is not happening though, it continues to pass the Empty String into the save() for the Object.

Question

What is going wrong or needs to be adjusted to have the Empty String set correctly to null when saving the Ojbject?

Code

Object

@Size(min = 1, max = 255)
@Column(length = 255)
private String businessTitle;

JacksonConfiguration

@Configuration
public class JacksonConfiguration {


  @Bean
  public Jackson2ObjectMapperBuilder filteringObjectMapperBuilder() {
    Jackson2ObjectMapperBuilder builder = new Jackson2ObjectMapperBuilder();
    builder.featuresToDisable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
    builder.featuresToEnable(DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT);

    return builder;
  }
}

Exception

Caused by: javax.validation.ConstraintViolationException: Validation failed for classes [com..model.User] during update time for groups [javax.validation.groups.Default, ]
List of constraint violations:[
      ConstraintViolationImpl{interpolatedMessage='size must be between 1 and 255', propertyPath=businessTitle, rootBeanClass=class com..model.User, messageTemplate='{javax.validation.constraints.Size.message}'}
]
        at org.hibernate.cfg.beanvalidation.BeanValidationEventListener.validate(BeanValidationEventListener.java:138)
        at org.hibernate.cfg.beanvalidation.BeanValidationEventListener.onPreUpdate(BeanValidationEventListener.java:86)
        at org.hibernate.action.internal.EntityUpdateAction.preUpdate(EntityUpdateAction.java:244)
        at org.hibernate.action.internal.EntityUpdateAction.execute(EntityUpdateAction.java:118)
        at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:582)
        at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:456)
        at org.hibernate.event.internal.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:337)
        at org.hibernate.event.internal.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:39)
        at org.hibernate.internal.SessionImpl.flush(SessionImpl.java:1282)
        at org.hibernate.internal.SessionImpl.managedFlush(SessionImpl.java:465)
        at org.hibernate.internal.SessionImpl.flushBeforeTransactionCompletion(SessionImpl.java:2963)
        at org.hibernate.internal.SessionImpl.beforeTransactionCompletion(SessionImpl.java:2339)
        at org.hibernate.engine.jdbc.internal.JdbcCoordinatorImpl.beforeTransactionCompletion(JdbcCoordinatorImpl.java:485)
        at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl.beforeCompletionCallback(JdbcResourceLocalTransactionCoordinatorImpl.java:147)
        at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl.access$100(JdbcResourceLocalTransactionCoordinatorImpl.java:38)
        at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl$TransactionDriverControlImpl.commit(JdbcResourceLocalTransactionCoordinatorImpl.java:231)
        at org.hibernate.engine.transaction.internal.TransactionImpl.commit(TransactionImpl.java:65)
        at org.hibernate.jpa.internal.TransactionImpl.commit(TransactionImpl.java:61)
        ... 127 common frames omitted
ALM
  • 2,555
  • 7
  • 31
  • 45
  • Did you read this? http://stackoverflow.com/questions/22688713/jackson-objectmapper-deserializationconfig-feature-accept-empty-string-as-null-o – Adam Dec 21 '16 at 21:58

2 Answers2

2

DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT is not going to help you because it means "deserialise empty string JSON value as null for object field" and unfortunately your String fields are scalars not JSON objects. I think there is no convenient way to get behaviour you want. It is possible to override deserializaton behaviour for all fields with type String but you may not want it. Also you can define custom deserialzer but you will need to annotate every field like this:

@JsonDeserialize(using = MyStringDeseralizer.class)
private String businessTitle;

where class MyStringDeseralizer extends JsonDeserializer<String> and implement conversion logic you need.

Alexander Yanyshin
  • 1,310
  • 10
  • 8
  • Thank you. I did read somewhere about setting up a custom JsonDeserialize in some other posts while searching for solutions. I will take a look into that. – ALM Dec 21 '16 at 22:04
  • A co-worker found a better solution than putting it on each attribute, and allows you to create it on every String.class type when deserializing. I posted the solution above. – ALM Dec 22 '16 at 00:01
0

Actually there is a better solution then having to put it on each attribute. Create a custom deserializer, EmptyToNullStringDeserializer, for changing '' to null. This is based on a co-workers solution.

builder
  .deserializerByType(String.class, new EmptyToNullStringDeserializer());
ALM
  • 2,555
  • 7
  • 31
  • 45