У меня есть модель, у которой есть HashMap
как вы видели ниже:
private Map<String, String> attrMap = new HashMap<String, String>();
и инициализировать его следующим образом:
attrMap.add("name", "value of name");
attrMap.add("content", "value of content");
но я хочу сериализовать это поле как ArrayList
таких объектов:
[{name: "value of name"}, {content: "value of content"}]
ОБНОВЛЕНИЕ 1
Есть ли способ вызвать функцию во время сериализации следующим образом:
@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());
}
ОБНОВЛЕНИЕ 2
Я использую этот класс для сериализации attrMap
, но get can not start an object expecting field name
ошибки can not start an object expecting field name
.
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();
}
}
}
Я начинаю Jackson
Следующая конструкция создаст желаемый результат:
@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"}]
}
Он использует комбинацию класса ObjectNode
от Jackson
вместе с некоторыми потоками Java 8 для сбора новых данных.
EDIT: после получения дополнительной информации от OP, где они попросили другой подход, я добавил эту альтернативу.
Другой подход - просто использовать @JacksonSerializer
для атрибута.
// 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); // ->
}
Таким образом, сериализация вытесняется с помощью сериализатора и POJO не поврежден.
[{"key":"name","value":"value of name"},{"key":"content","value":"value of content"}]
.
Если вы не против делать это вручную, тогда возьмите следующий код (не тестировался, но должен работать):
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());
Это, вероятно, самый простой способ сделать это, поскольку, если вы хотите использовать библиотеку JSON, вам нужно либо изменить вывод (не рекомендуется, так как он накладывает плохую ремонтопригодность), либо написать собственный сериализатор/десериализатор для HashMap, который будет более сложным.
Попробуйте с помощью метода keySet и значений, который возвращает набор ключей и значений, а затем преобразует в arraylist что-то вроде:
List<String> keyList = new ArrayList<>(attrMap.keySet());
List<String> valueList = new ArrayList<>(attrMap.values());
Чтобы быть очень конкретным для вашего вопроса, вам нужно что-то вроде:
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"}]
Отметьте в стороне: в вашем посте кажется опечатка, так как на карте нет метода добавления. надеюсь, что вы имели в виду "положить" и "не добавлять". Также есть утилиты, такие как Gson, Jackson и т.д., Которые можно конвертировать в json-объект.
@JsonSerialize
@JsonSerialize так, как вы запрашивали. Вам нужно предоставить класс, который наследуетJsonSerializer
.