Custom serializer for serializing a List<User> in List<String>

13,365

Solution 1

I suggest that you look into Jackson's Converter interface, which seems more suited to the task than creating a custom serializer.

One approach it to create a Converter instance and add it to the ObjectMapper, so that it will be used for the serialization of all User instances.

public class UserConverter extends StdConverter<User, String> {
    @Override
    public String convert(User user) {
        return user.getTitle();
    }
}

Register it on your ObjectMapper like this:

SimpleModule simpleModule = new SimpleModule();
simpleModule.addSerializer(User.class, new StdDelegatingSerializer(new UserConverter()));

ObjectMapper om = new ObjectMapper().registerModule(simpleModule);

Another approach, in case you don't want to convert all User instances to String, is to annotate selected properties with a converter like this:

public class Group {
    String title;
    @JsonSerialize(converter = ListUserConverter.class)
    List<User> members;
    String createdBy;
}

And have a corresponding converter that looks something like this:

public class ListUserConverter extends StdConverter<List<User>, List<String>> {
    @Override
    public List<String> convert(List<User> users) {
        return users.stream().map(User::getTitle).collect(Collectors.toList());
    }
}

Solution 2

Try like below :

Group:

@JsonIgnoreProperties(ignoreUnknown=true)
public class Group {

    @JsonSerialize(using= TitleSerializer.class)    
    List<User> members;

   //getters and setters 
}

User:

public class User {

    private String title;

    //getters and setters
}

Custom Serializer :

public class TitleSerializer extends StdSerializer<List<User>> {


    private static List<User> users=new ArrayList<User>();

    protected TitleSerializer(Class<List<User>> t) {
        super(t);
        // TODO Auto-generated constructor stub
    }

    @SuppressWarnings("unchecked")
    public TitleSerializer(){
          this((Class<List<User>>) users.getClass());     

    }

    @Override
    public void serialize(List<User> users, JsonGenerator paramJsonGenerator,
            SerializerProvider paramSerializerProvider) throws IOException {

        paramJsonGenerator.writeStartObject();
        List<String> titles=new ArrayList<String>(users.size());
        for(User user: users){
            titles.add(user.getTitle());
        }
        paramJsonGenerator.writeObjectField("members", titles);
        paramJsonGenerator.writeEndObject();
    }

}

Test :

Group group=new Group(Arrays.asList(new User("a"),new User("b"),new User("c")));
ObjectMapper mapper = new ObjectMapper();       
String serialized = mapper.writeValueAsString(group);
System.out.println("output "+serialized);

Output:

{"members":["a","b","c"]}
Share:
13,365
crysis
Author by

crysis

Updated on July 29, 2022

Comments

  • crysis
    crysis over 1 year

    I've a Model object Group

    public class Group {
        String title;
        List<User> members;
        String createdBy;
    }
    

    I'm using Jackson to serialize this Object. Instead of serializing the whole User object in list "members" I want to serializer just the user.getTitle() field. Basically I want a HashMap to be something like

    {
      "title" : "sometitle"
      "members" : [user1.getTitle(), user2.getTitle()]
    }
    

    I've written a custom serializer for this

    public class GroupSerializer extends JsonSerializer<Circle> {
    
        @Override
        public void serialize(Group value, JsonGenerator gen, SerializerProvider serializers) throws IOException, JsonProcessingException {
    
            if(value != null) {
                gen.writeStartObject();
                gen.writeStringField("title", value.getTitle());
                gen.writeStringField("createdBy", value.getCreatedBy());
                gen.writeFieldName("members");
                gen.writeStartArray();
                for(User user : value.getMembers()) {
                    gen.writeString(user.getEmail());
                }
                gen.writeEndArray();
                gen.writeEndObject()
            }
       }
    }
    

    But it's not working. How do I serialize only a field of List instead of whole User Object?

  • crysis
    crysis over 7 years
    This is what im looking for. Thanks. But what is that stream() function?
  • Henrik Aasted Sørensen
    Henrik Aasted Sørensen over 7 years
    Good to hear it! :) The stream() thing is a Java 8 thing (Read more), and is not mandatory. Feel free to convert the list the way you usually would.
  • crysis
    crysis over 7 years
    It's similar to RxJava Observable. Thanks dude. Your solution worked.
  • Andrew T Finnell
    Andrew T Finnell over 5 years
    I'm curious why this isn't the Accepted Answer, or at the very least why it was down voted. This appears to be exactly what is needed.
  • mzl
    mzl over 5 years
    Because this is not working. Don't waste your time on this answer. The output is: output {"members":{"members":["a","b","c"]}}
  • tete
    tete over 4 years
    I used this to filter a list using an element's property (isHidden()) since Jackson 2.8 doesn't have JsonInclude.Include.CUSTOM feature, it's incorporated in 2.9.
  • Alessandro Scarlatti
    Alessandro Scarlatti over 2 years
    Since Jackson 2.2 you can also use @JsonSerialize(contentConverter=UserConverter.class) for a List<User> field. This way, you can use a single converter class for a User field or List<User> field.