Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I get a Jackson mixin to work with private fields?

I was experimenting with Jackson 2.0 mixins to serialize a class with no annotations.

Simplified source code below. Note that I'm not using getters/setters, but it seemed like I should still be able to use mixins according to the documentation.

public class NoAnnotation {
   private Date created;
   private String name;

   // make one with some data in it for the test
   static NoAnnotation make() {
      NoAnnotation na= new NoAnnotation();
      na.created = new Date();
      na.name = "FooBear";
      return na;
   }

   // my Mixin "class"
   static class JacksonMixIn {
      JacksonMixIn(@JsonProperty("created") Date created,
                   @JsonProperty("name") String name)
         { /* do nothing */ }
   }

   // test code
   public static void main(String[] args) throws Exception {
      NoAnnotation na = NoAnnotation.make();
      ObjectMapper objectMapper = new ObjectMapper();
      objectMapper.addMixInAnnotations(NoAnnotation.class, JacksonMixIn.class);
      String jsonText = objectMapper.writeValueAsString(na);
      System.out.println(jsonText);
   }
}

When I run main I get

Exception in thread "main" com.fasterxml.jackson.databind.JsonMappingException: No serializer found for class com.flyingspaniel.so.NoAnnotation and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationConfig.SerializationFeature.FAIL_ON_EMPTY_BEANS) )
    at com.fasterxml.jackson.databind.ser.impl.UnknownSerializer.failForEmpty(UnknownSerializer.java:51)
    at com.fasterxml.jackson.databind.ser.impl.UnknownSerializer.serialize(UnknownSerializer.java:25)
    at com.fasterxml.jackson.databind.ser.DefaultSerializerProvider.serializeValue(DefaultSerializerProvider.java:108)
    at com.fasterxml.jackson.databind.ObjectMapper._configAndWriteValue(ObjectMapper.java:2407)
    at com.fasterxml.jackson.databind.ObjectMapper.writeValueAsString(ObjectMapper.java:1983)
    at com.flyingspaniel.so.NoAnnotation.main(NoAnnotation.java:49)

When I follow the instructions in the Exception and add a line

objectMapper.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS);

I no longer get an exception, but the result is an empty JSON object, {}.

If I make the fields public it works, but that is not something I want to do, as it's not a reasonable object design.

I'm guessing that I am leaving out a basic "setThis" step somewhere, but don't know what. How can I get mixins to work in this situation?

like image 938
user949300 Avatar asked Jun 07 '12 18:06

user949300


2 Answers

I figured it out. If you want to access private fields, you need to play with the Visibility by adding the following line:

objectMapper.setVisibilityChecker(VisibilityChecker.Std.defaultInstance()
        .withFieldVisibility(Visibility.ANY));

For protected fields, you could also use Visibility.PROTECTED_AND_PUBLIC.

Full example

// test code
public static void main(String[] args) throws Exception {
   NoAnnotation na = NoAnnotation.make();
   ObjectMapper objectMapper = new ObjectMapper();
   objectMapper.addMixInAnnotations(NoAnnotation.class, JacksonMixIn.class);
   objectMapper.setVisibilityChecker(VisibilityChecker.Std.defaultInstance()
           .withFieldVisibility(Visibility.ANY));
   String jsonText = objectMapper.writeValueAsString(na);
   System.out.println(jsonText);
}
like image 108
user949300 Avatar answered Nov 09 '22 13:11

user949300


If you want use the annotation mixin the correct way to declare it is:

static class JacksonMixIn {
    @JsonProperty Date created;
    @JsonProperty String name;
}

When done in this way you can control the fields to serialize simply including/excluding them from the mix in.

like image 31
carlo.polisini Avatar answered Nov 09 '22 13:11

carlo.polisini