Rasool Ghafari
Rasool Ghafari

Reputation: 4258

How to serialize HashMap as ArrayList as JSON?

I have a model that have a HashMap as you seen below:

private Map<String, String>     attrMap     = new HashMap<String, String>();

and initialize it like this:

attrMap.add("name", "value of name");
attrMap.add("content", "value of content");

but i want to serialize this field as a ArrayList of objects like this:

[{name: "value of name"}, {content: "value of content"}]

UPDATE 1

Is there a way to call a function during serialization like this:

@JsonSerializer(serializeAttrMap)
private Map<String, String>     attrMap     = new HashMap<String, String>();

public String serializeAttrMap() {
    ArrayList<String> entries = new ArrayList<>(this.attrMap.size());
    for(Map.Entry<String,String> entry : attrMap.entrySet())
        entries.add(String.format("{%s: \"%s\"}",
            entry.getKey(), entry.getValue()));
    return Arrays.toString(entries.toArray());
}

UPDATE 2

I use this class to serialize attrMap, but get can not start an object expecting field name error.

import java.io.IOException;
import java.util.Map;

import org.codehaus.jackson.JsonGenerator;
import org.codehaus.jackson.JsonProcessingException;
import org.codehaus.jackson.map.JsonSerializer;
import org.codehaus.jackson.map.SerializerProvider;

public class AttrMapSerializer extends JsonSerializer<Map<String, String>> {

        @Override
        public void serialize(Map<String, String> attributes, JsonGenerator generator, SerializerProvider provider) throws IOException, JsonProcessingException {
            for (Map.Entry<String, String> attribute : attributes.entrySet())
            {
                generator.writeStartObject();
                generator.writeObjectField("name", attribute.getKey());
                generator.writeObjectField("content", attribute.getValue());
                generator.writeEndObject();
            }
        }
    }

I'm beginner to Jackson

Upvotes: 2

Views: 5363

Answers (3)

wassgren
wassgren

Reputation: 19201

The following construct will create the desired output:

@Test
public void testJackson() throws JsonProcessingException {
    // Declare the map
    Map<String, String> attrMap = new HashMap<>();

    // Put the data in the map
    attrMap.put("name", "value of name");
    attrMap.put("content", "value of content");

    // Use an object mapper
    final ObjectMapper objectMapper = new ObjectMapper();

    // Collect to a new object structure
    final List<ObjectNode> collected = attrMap.entrySet()
            .stream()
            .map(entry -> objectMapper.createObjectNode().put(entry.getKey(), entry.getValue()))
            .collect(Collectors.toList());

    // The output
    final String json = objectMapper.writeValueAsString(collected);

    System.out.println(json); // -> [{"name":"value of name"},{"content":"value of content"}]
}

It uses a combination of the ObjectNode class from Jackson together with some Java 8 streams to collect the new data.

EDIT: After more info from the OP where they requested another approach I added this alternative.

Another approach is to simply use a @JacksonSerializer on the attribute.

// This is the serializer
public static class AttrMapSerializer extends JsonSerializer<Map<String, String>> {
    @Override
    public void serialize(
            final Map<String, String> value,
            final JsonGenerator jgen, final SerializerProvider provider) throws IOException {

        // Iterate the map entries and write them as fields
        for (Map.Entry<String, String> entry : value.entrySet()) {
            jgen.writeStartObject();
            jgen.writeObjectField(entry.getKey(), entry.getValue());
            jgen.writeEndObject();
        }
    }
}

// This could be the POJO
public static class PojoWithMap {
    private Map<String, String> attrMap = new HashMap<>();

    // This instructs the ObjectMapper to use the specified serializer
    @JsonSerialize(using = AttrMapSerializer.class)
    public Map<String, String> getAttributes() {
        return attrMap;
    }
}

public static void main(String... args) throws JsonProcessingException {
    final PojoWithMap pojoWithMap = new PojoWithMap();
    pojoWithMap.getAttributes().put("name", "value of name");
    pojoWithMap.getAttributes().put("content", "value of content");


    final String json = new ObjectMapper().writeValueAsString(pojoWithMap);
    System.out.println(json); // ->
}

This way the serialization is externalized to a serializer and the POJO is intact.

Upvotes: 2

Haochen Xie
Haochen Xie

Reputation: 390

If you don't mind doing it manually, then take the following code (not tested, but should work):

ArrayList<String> entries = new ArrayList<>(attrMap.size());
for(Map.Entry<String,String> entry : attrMap.entrySet())
    entries.add(String.format("{%s: \"%s\"}",
            entry.getKey(), entry.getValue()));
return Arrays.toString(entries.toArray());

This is probably the easiest way to do it, since if you want to use a JSON library, you have to either modify the output (not recommended since it imposes bad maintainability), or write a custom serializer/deserializer for HashMap, which will be more complicated.

Upvotes: 0

SMA
SMA

Reputation: 37023

Try with keySet and values method which returns set of keys and values and then convert to arraylist with something like:

List<String> keyList = new ArrayList<>(attrMap.keySet());
List<String> valueList = new ArrayList<>(attrMap.values());

To be very specific to your question, you need something like:

final Map<String, String>     attrMap     = new HashMap<String, String>();
attrMap.put("name", "value of name");
attrMap.put("content", "value of content");
List<String> keyList = new ArrayList<>(attrMap.size());
for (Map.Entry<String, String> entry : attrMap.entrySet()) {//iterate over map
  keyList.add("{" + entry.getKey() + ": \"" + entry.getValue() + "\"}");//add key followed by value
}
System.out.println(keyList);

Output:
[{name: "value of name"}, {content: "value of content"}]

Note aside: It seems typo in your post as there is no add method in map. hope you meant put and not add. Also there are utilities like Gson, jackson etc avaiable to convert to json object.

Upvotes: 0

Related Questions