Reputation: 4258
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
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
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
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