2016-03-14 2 views
1

Мне нужно было преобразовать объекты java в Map<String, String> для обложки api REST, которую я пишу. Любые поля, которые были сложными объектами, должны были быть сериализованы для json. Я понял, как сделать это так:Как преобразовать карту <String, String> с значениями json в POJO с помощью джексона?

public static Map<String, String> toContentMap(Object object) throws JsonProcessingException { 
    Map<String, Object> objectParamMap = MAPPER.convertValue(object, new TypeReference<Map<String, Object>>() {}); 
    Map<String, String> contentMap = new HashMap<>(); 

    for (Entry<String, Object> entry : objectParamMap.entrySet()) { 
     String key = entry.getKey(); 
     String value = MAPPER.writeValueAsString(entry.getValue()); 
     contentMap.put(key, StringUtils.strip(value, "\"")); 
    } 

    return contentMap; 
} 

Теперь мне нужен способ, чтобы получить от этого Map<String, String> представления в объект Pojo. Можно ли это сделать, используя в основном jackson apis?

Редактировать:

Я думаю, я был неясно. Я знаю POJO, из которого я иду/из. Но он должен быть общим и работать для любого базового POJO.

Пример:

class MyObject { 
    String fieldA; 
    Long fieldB; 
    MyOtherObject fieldC; 
    List<String> fieldD; 
} 

class MyOtherObject { 
    String fieldA; 
    String fieldB; 
} 

MyObject object = new MyObject("valueA", 20L, 
     new MyOtherObject("valueA", "valueB"), 
     Lists.newArrayList("array1", "array2")); 

Map<String, String> contentMap = toContentMap(object); 
/* 
"fieldA" -> "valueA" 
"fieldB" -> "20" 
"fieldC" -> "{\"fieldA\":\"valueA\",\"fieldB\":\"valueB\"}" 
"fieldD" -> "[\"array1\",\"array2\"]" 
*/ 

MyObject newObject = fromContentMap(contentMap); 
assertEquals(object, newObject) 
+0

Сам 'JSONObject' в основном представляет собой« Map ', так зачем вам нужно преобразовывать в« Map »? –

+0

Было бы также полезно, если бы вы включили в свой вопрос объект POJO. –

+0

Если вы не знаете, к какому классу следует десериализовать, то как вы могли бы создать экземпляр этого неизвестного класса? –

ответ

1

Основываясь на ваш комментарий

он должен работать для любого POJO я прошу его

Я думаю, что вы ищете @JsonAnyGetter и @JsonAnySetter аннотаций, который присвоит значения, что он может к POJO (который вам нужно указать при десериализации ... он не может быть общим), но будет придерживаться всего, что не анализируется в Map<String, Object>.

Обратите внимание, что это не может быть Map<String, String>, потому что JSON содержит больше, чем просто значения строк.

Например, возьмите JSON

{ 
    "uid": 1, 
    "username": "steve", 
    "email": "[email protected]" 
} 

Вы можете generate a Jackson POJO что выглядит так.

import com.fasterxml.jackson.annotation.JsonAnyGetter; 
import com.fasterxml.jackson.annotation.JsonAnySetter; 
import com.fasterxml.jackson.annotation.JsonIgnore; 
import com.fasterxml.jackson.annotation.JsonInclude; 
import com.fasterxml.jackson.annotation.JsonProperty; 
import com.fasterxml.jackson.annotation.JsonPropertyOrder; 

@JsonInclude(JsonInclude.Include.NON_NULL) 
@JsonPropertyOrder({ 
     "uid", 
     "username", 
     "email" 
}) 
public class User { 

    @JsonProperty("uid") 
    private Integer uid; 
    @JsonProperty("username") 
    private String username; 
    @JsonProperty("email") 
    private String email; 
    @JsonIgnore 
    private Map<String, Object> additionalProperties = new HashMap<String, Object>(); 

    @JsonProperty("uid") 
    public Integer getUid() { 
     return uid; 
    } 

    @JsonProperty("uid") 
    public void setUid(Integer uid) { 
     this.uid = uid; 
    } 

    @JsonProperty("username") 
    public String getUsername() { 
     return username; 
    } 

    @JsonProperty("username") 
    public void setUsername(String username) { 
     this.username = username; 
    } 

    @JsonProperty("email") 
    public String getEmail() { 
     return email; 
    } 

    @JsonProperty("email") 
    public void setEmail(String email) { 
     this.email = email; 
    } 

    @JsonAnyGetter 
    public Map<String, Object> getAdditionalProperties() { 
     return this.additionalProperties; 
    } 

    @JsonAnySetter 
    public void setAdditionalProperty(String name, Object value) { 
     this.additionalProperties.put(name, value); 
    } 

} 
1

Вы можете использовать

ObjectMapper mapper = new ObjectMapper(); 
String jsonInString = "{'name' : 'rahul'}"; 


//JSON from String to Object 
User user = mapper.readValue(jsonInString, User.class); 

или

User user = mapper.convertValue(map, User.class); 

если вы конвертируете из JSon/карты для пользовательского объекта. Вы также можете передавать информацию о типе в процесс сериализации/десериализации, чтобы джексон знал о внутренних компонентах. Пожалуйста, прочитайте больше об этом here.

+0

Это не сработает. Как он узнает, к какому классу десериализовать объект? –

+0

Я предполагаю, что пользователь знает, в каком классе он будет десериализовать объект. Если нет, ему нужно будет получить эту информацию, передав дополнительные конструкции метаданных на json или или внешнюю структуру данных – rahulbmv

0

Мы не можем этого сделать. Я боюсь. Когда object сериализуется в JSON String, он теряет тип класса. Таким образом, десериализуя строку в объект, парсер не знает, какой класс будет десериализовать объект. Тем не менее, есть несколько способов сделать это:

магазин информация типа в другой карте:

Создать новый map как это:

Map<String, Class> metaData = new HashMap<>(); 

Он будет хранить имя типа вместе с классом. Итак, в то время как derializing, мы можем искать тип класса с этой карты и передать его методу readValue.

Использование @Type аннотацию ObjectMapper: (только полезно, если все объекты распространяются и тот же базовый класс)

Яксон имеет функцию Polymorphic Deserialization, которая поможет десериализации в объект, если все классы наследуют общий базовый класс. Взгляните на документацию here.