2017-05-08 31 views
0

亲爱的人们我需要你的建议。将json嵌入式节点反序列化为值使用Jackson的地图

我是,试图实现自定义Jackson解串器的地图,但有困难。作为输入数据,我有以下的JSON:

{ 
    "someMap": { 
     "one_value": "1", 
     "another_value: "2" 
    }, 
    "anotherMap": "{\"100000000\": 360000,\"100000048\": 172800,\"100000036\": 129600,\"100000024\": 86400,\"100000012\": 43200}" 
} 

正如你可以在它节点值内JSON地图(我做那样的意向第二种情况中看到,因为我想要更换。来自env变量的值:"anotherMap": "${SOME_MAP:-{\"100000000\": 360000,\"100000048\": 172800,\"100000036\": 129600,\"100000024\": 86400,\"100000012\": 43200}}")。据我了解,我必须区分这两个地图反序列化流程。所以对于第一个映射,我需要使用默认的一个映射反序列化器作为第二个自定义映射器,以便从值中正确解析映射。目前,我写的代码来做到这一点:

// invokation code 
new ObjectMapper().registerModule(new ConfigModule()).readValue(is, ConfigModuleTestConfigWrapper.class); 

// module code 
public class ConfigModule extends SimpleModule { 

@Override 
public void setupModule(SetupContext context) { 
    super.setupModule(context); 
    context.addDeserializers(new Deserializers.Base() { 

      @Override 
      public JsonDeserializer<?> findMapDeserializer(MapType type, DeserializationConfig config, BeanDescription beanDesc, 
                 KeyDeserializer keyDeserializer, TypeDeserializer elementTypeDeserializer, 
                 JsonDeserializer<?> elementDeserializer) throws JsonMappingException { 
       return new MapPropertyDeserializer(type); 
      } 
    }); 
} 

private static class MapPropertyDeserializer extends StdScalarDeserializer<Map<String, Integer>> { 
    MapPropertyDeserializer(MapType type) { 
     super(type); 
    } 
    @Override 
    public Map<String, Integer> deserialize(JsonParser p, DeserializationContext ctxt) throws IOException { 
     JsonNode node = p.readValueAsTree(); 
     if (node == null || node.isContainerNode()) { 
       // return <default jackson deserializer> 
     } 
     System.out.println("isContainerNode ?: " + node.isContainerNode()); 
     System.out.println("isValueNode ?: " + node.isValueNode()); 
     // some parsing flow goes below 
     JsonNode valueNode = node.get(1); 
     valueNode.asText(); 
     return new HashMap<>(); 
    } 
} 

// bean description 
@JsonIgnoreProperties 
public class ConfigSubstitutorModuleTestConfigWrapper { 

    private final Map<String, String> someMap; 
    private final Map<String, Integer> anotherMap; 

    @JsonCreator 
    public ConfigSubstitutorModuleTestConfigWrapper(
      @JsonProperty("someMap") Map<String, String> someMap, 
      @JsonProperty("anotherMap") Map<String, Integer> anotherMap 

) { 
     this.someMap = someMap; 
     this.anotherMap = anotherMap; 
    } 

    public Map<String, String> getSomeMap() { 
     return someMap; 
    } 
    public Map<String, Integer> getAnotherMap() { 
     return anotherMap; 
    } 
} 

的问题是(我的理解:)),我不知道如何从反序列化方法返回默认地图解串器。

有没有人有任何线索我可以在那里做到达到预期的目标?

+0

你不能修复而产生的内部JSON这个丑陋的JSON字符串的一部分?这是看起来破碎的部分。 –

+0

我不能那样做。这里的想法是用环境变量中的值替换那个丑陋的json,比如''anotherMap“:”$ {SOME_MAP: - {\“100000000 \”:360000,\“100000048 \”:172800,\“100000036 \”: 129600,\“100000024 \”:86400,\“100000012 \”:43200}}“'。 所以我按意愿去做。 –

+0

可能的重复http://stackoverflow.com/questions/18313323/how-do-i-call-the-default-deserializer-from-a-custom-deserializer-in-jackson –

回答

0

最终接受了解决方案解决它:

1)创建解串器类:

/** 
* The target of that deserializer is to do two-step deserialization. 
* At first it just reads string and then does second deserialization in the proper {@link Map} type once string substitution done. 
* <p> 
* Note! In order to get object mapper reference you have to set it first on object mapper initialization stage: 
* </p> 
* <pre> 
*  objectMapper.setInjectableValues(new InjectableValues.Std().addValue(OBJECT_MAPPER_VALUE_ID, objectMapper)); 
* </pre> 
*/ 
public class ValueAsMapDeserializer extends JsonDeserializer<Map> implements ContextualDeserializer { 
    public static final String OBJECT_MAPPER_VALUE_ID = "objectMapper"; 
    static final String VALUE_PREFIX = "$|"; 
    static final String VALUE_SUFFIX = "|"; 

    private JavaType keyType; 
    private JavaType valueType; 

    @Override 
    public JsonDeserializer<?> createContextual(final DeserializationContext ctxt, 
               final BeanProperty property) throws JsonMappingException { 
     JavaType filedType = property.getType(); 
     this.keyType = filedType.getKeyType(); 
     this.valueType = filedType.getContentType(); 
     return this; 
    } 

    @Override 
    public Map deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException { 
     // Can't use constructor init there because of intention to use that deserializer using annotation 
     // Also such tricky thing as 'injectable values' was used cause of no way to get the reference to object mapper from deserialization context out of the box 
     ObjectMapper objectMapper = (ObjectMapper) ctxt.findInjectableValue(OBJECT_MAPPER_VALUE_ID, null, null); 
     final Optional<String> substitutedValue = Substitutor.create(jp, VALUE_PREFIX, VALUE_SUFFIX).substitute(); 
     MapType mapType = objectMapper.getTypeFactory().constructMapType(Map.class, keyType, valueType); 
     return objectMapper.readValue(substitutedValue.orElseThrow(() -> new RuntimeException("Failed to parse the value as map")), mapType); 
    } 
} 

2)马克bean字段使用该解串器:

@JsonDeserialize(using = ValueAsMapDeserializer.class) 
private final Map<String, Integer> anotherMap; 
0

尝试分两步进行反序列化:

package stack43844461; 

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

import org.junit.Test; 

import com.fasterxml.jackson.core.JsonParseException; 
import com.fasterxml.jackson.databind.JsonMappingException; 
import com.fasterxml.jackson.databind.ObjectMapper; 

public class HowToConvertJsonStringToMap { 

    @Test 
    public void json() throws JsonParseException, JsonMappingException, IOException { 

     String jsonInString = "{\"someMap\":" 
         + " {\"one_value\": \"1\"," 
         + "\"another_value\": \"2\"}," 
         + "\"anotherMap\": " 
         + "\"{\\\"100000000\\\": 360000," 
         + "\\\"100000048\\\": 172800," 
         + "\\\"100000036\\\": 129600," 
         + "\\\"100000024\\\": 86400," 
         + "\\\"100000012\\\": 43200}\"}"; 

     ObjectMapper mapper = new ObjectMapper(); 
     // Step 1: Read everything into one object. 
     Map<String, Object> all = mapper.readValue(jsonInString, Map.class); 
     // Step 2: Get your "normal" data into one object 
     Map<String, Object> someMap=(Map<String, Object>) all.get("someMap"); 
     // Step 3: Get your "embedded" data from your object 
     String anotherMapStr = (String) all.get("anotherMap"); 
     // Step 4: Deserialize embedded data 
     Map<String, Object> anotherMap = mapper.readValue(anotherMapStr, Map.class); 
     System.out.println(anotherMap); 
     System.out.println(someMap); 
    } 

} 

打印:

{100000000=360000, 100000048=172800, 100000036=129600, 100000024=86400, 100000012=43200} 
{one_value=1, another_value=2} 
+0

是的,它可能会适用于我的情况。但我必须使用将为objectMapper注册的模块,所以我需要在反序列化程序中执行此操作,而不是使用'jsonInString'我在类型为Map的POJO中包含字段,并且不知道像anotherMap这样的确切字段名称, –

相关问题