2016-01-16 20 views
0

我想用Jackson解析JSON文檔,並在所有節點上應用一些轉換。例如,假設我希望反序列化後所有值都是大寫的。如何在使用Jackson反序列化Json時對所有值應用轉換

實際使用情況更復雜一點:

  • 改造比較複雜,變壓器類需要一些配置來注射的,我想這是一個configureable實例
  • 轉型必須在所有屬性上發生,我希望能夠不對每個反序列化類的每個屬性添加批註。

Jackson有足夠的配置選項/鉤子,所以我相當肯定這是可能的,我找不到我的方式。

下面的測試表明我想要實現:

public class JsonValueFilterTest { 

    private ObjectMapper mapper; 

    @Before 
    public void setupObjectMapper() { 
     mapper = new ObjectMapper(); 
     // TODO: configure mapper to upper case all values 
    } 

    @Test 
    public void printJson() throws IOException { 
     Entity myEntity = new Entity("myName"); 
     mapper.writeValue(System.out, myEntity); // prints: {"name":"myName"} 
    } 

    @Test 
    public void valuesAreUpperCasedWhenLoaded() throws IOException { 
     Entity myEntity = mapper.readValue("{\"name\":\"myName\"}", Entity.class); 
     assertThat(myEntity.getName()).isEqualTo("MYNAME"); // fails 
    } 

    public static class Entity { 
     private final String name; 

     @JsonCreator 
     public Entity(@JsonProperty("name") String name) { this.name = name; } 

     public String getName() { return name; } 

     @Override 
     public String toString() { return "name='" + name + "'"; } 
    } 
} 

回答

1

我的最終解決方案(感謝阿爾班):

  1. 配置ObjectMapper使用自定義JsonNodeFactory,其將所有文本節點
  2. 反序列化JSON來JsonNode(這將應用轉化)
  3. JsonNode轉換爲我的自定義類

    public class JsonValueFilterTest {

    private ObjectMapper mapper; 
    
    @Before 
    public void setupObjectMapper() { 
        mapper = new ObjectMapper(); 
        mapper.setNodeFactory(new JsonNodeFactory() { 
         @Override 
         public TextNode textNode(String text) { 
          return super.textNode(text.toUpperCase()); 
         } 
        }); 
    } 
    
    @Test 
    public void printJson() throws IOException { 
        Entity myEntity = new Entity("myName"); 
        mapper.writeValue(System.out, myEntity); // prints: {"name":"myName"} 
    } 
    
    @Test 
    public void valuesAreUpperCasedWhenLoaded() throws IOException { 
        JsonNode jsonNode = mapper.readTree("{\"name\":\"myName\"}"); 
        Entity myEntity = mapper.treeToValue(jsonNode, Entity.class); 
        assertThat(myEntity.getName()).isEqualTo("MYNAME"); 
    } 
    
    public static class Entity { 
        private final String name; 
    
        @JsonCreator 
        public Entity(@JsonProperty("name") String name) { this.name = name; } 
    
        public String getName() { return name; } 
    
        @Override 
        public String toString() { return "name='" + name + "'"; } 
    } 
    

    }

3

您可以使用轉換爲簡單的情況下,不實現自定義解串器。雖然我不知道爲什麼,但它並不適用於創作者構造函數。所以你將不得不使用非final字段。

public class JsonValueFilterTest { 

    private ObjectMapper mapper; 

    @BeforeTest 
    public void setupObjectMapper() { 
     mapper = new ObjectMapper(); 
    } 

    @Test 
    public void printJson() throws IOException { 
     Entity myEntity = new Entity("myName"); 
     mapper.writeValue(System.out, myEntity); // prints: {"name":"myName"} 
    } 

    @Test 
    public void valuesAreUpperCasedWhenLoaded() throws IOException { 
     Entity myEntity = mapper.readValue("{\"name\":\"myName\"}", Entity.class); 
     Assert.assertEquals(myEntity.getName(), "MYNAME"); // fails 
    } 

    public static class UpCaseConverter extends StdConverter<String, String> { 
     public String convert(String value) { 
      return value==null ? null : value.toUpperCase(); 
     } 
    } 

    public static class Entity { 

     private String name; 

     public Entity() {} 

     public Entity(String name) { 
      this.name = name; 
     } 

     @JsonDeserialize(converter = UpCaseConverter.class) 
     public void setName(String name) { 
      this.name = name; 
     } 

     public String getName() { 
      return name; 
     } 

     @Override 
     public String toString() { 
      return "name='" + name + "'"; 
     } 
    } 
} 
+0

我的使用情況實際上比這更復雜一點。我會更新這個問題。 – Guillaume

相關問題