8

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?

M. Justin
  • 14,487
  • 7
  • 91
  • 130
user949300
  • 15,364
  • 7
  • 35
  • 66

3 Answers3

7

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);
}
M. Justin
  • 14,487
  • 7
  • 91
  • 130
user949300
  • 15,364
  • 7
  • 35
  • 66
7

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.

M. Justin
  • 14,487
  • 7
  • 91
  • 130
carlo.polisini
  • 306
  • 4
  • 10
2

As mentioned in your self-answer, changing the field visibility checker will resolve this situation. As an alternative to modifying the ObjectMapper, this can be done with a purely annotation-based solution by using the @JsonAutoDetect annotation:

@JsonAutoDetect(fieldVisibility = Visibility.ANY)
static class JacksonMixIn {
   JacksonMixIn(@JsonProperty("created") Date created,
                @JsonProperty("id") int id)
      { /* do nothing */ }
}
M. Justin
  • 14,487
  • 7
  • 91
  • 130