2014-11-04 183 views
5

當我序列化/反序列化任何對象時,所有字段名都轉換爲小寫。 是否有任何配置可以讓Jackson將字段名稱保持原樣?序列化和反序列化?Jackson ObjectMapper大/小寫問題

(我知道@JsonProperty,但這並不似乎是正確的,因爲我需要的僅僅是傑克遜尊重已經存在的東西)

我的測試代碼:

import java.io.Serializable; 

import com.fasterxml.jackson.databind.DeserializationFeature; 
import com.fasterxml.jackson.databind.ObjectMapper; 
import com.fasterxml.jackson.databind.PropertyNamingStrategy; 
import com.fasterxml.jackson.databind.SerializationFeature; 
import com.fasterxml.jackson.databind.cfg.MapperConfig; 
import com.fasterxml.jackson.databind.introspect.AnnotatedField; 
import com.fasterxml.jackson.databind.introspect.AnnotatedMethod; 

public class Test { 

    static class Example implements Serializable { 
     private String Test; 
     private String ABC; 
     private String XyZ; 

     public String getTest() { return Test; } 
     public void setTest(String test) { Test = test; } 

     public String getABC() { return ABC; } 
     public void setABC(String abc) { ABC = abc; } 

     public String getXyZ() { return XyZ; } 
     public void setXyZ(String xyz) { XyZ = xyz; } 
    } 

    static class MyPropertyNamingStrategy extends PropertyNamingStrategy { 
     @Override 
     public String nameForField(MapperConfig<?> config, AnnotatedField field, String defaultName) { 
      return convert(defaultName); 
     } 
     @Override 
     public String nameForGetterMethod(MapperConfig<?> config, AnnotatedMethod method, String defaultName) { 
      return convert(defaultName); 
     } 
     @Override 
     public String nameForSetterMethod(MapperConfig<?> config, AnnotatedMethod method, String defaultName) { 
      return convert(defaultName); 
     } 
     private String convert(String input) { 
      return input; 
     } 
    } 

    public static void main(String[] args) throws Exception { 
     ObjectMapper objectMapper = new ObjectMapper() 
     .setPropertyNamingStrategy(new MyPropertyNamingStrategy()) 
     .enable(SerializationFeature.INDENT_OUTPUT) 
     .configure(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY, true);  

     //From OBJECT to JSON 
     Example ex = new Example(); 
     ex.setTest("1"); 
     ex.setABC("2"); 
     ex.setXyZ("3"); 
     System.out.println(objectMapper.writeValueAsString(ex)); 

     //FROM JSON to OBJECT 
     String jsonString = "{ \"Test\":\"0\", \"ABC\":\"1\", \"XyZ\":\"2\" }"; 
     Example fEx = objectMapper.readValue(jsonString, Example.class); 
    } 

} 

謝謝到@ BlueLettuce16,我已經設法構建了一個'改進'版本的PropertyNamingStrategy。那就是:

import java.lang.reflect.Modifier; 

import com.fasterxml.jackson.databind.PropertyNamingStrategy; 
import com.fasterxml.jackson.databind.cfg.MapperConfig; 
import com.fasterxml.jackson.databind.introspect.AnnotatedField; 
import com.fasterxml.jackson.databind.introspect.AnnotatedMethod; 

public class CustomPropertyNamingStrategy extends PropertyNamingStrategy { 

    @Override 
    public String nameForField(MapperConfig<?> config, AnnotatedField field, String defaultName) { 
     return convertForField(defaultName); 
    } 

    @Override 
    public String nameForGetterMethod(MapperConfig<?> config, AnnotatedMethod method, String defaultName) { 
     return convertForMethod(method, defaultName); 
    } 

    @Override 
    public String nameForSetterMethod(MapperConfig<?> config, AnnotatedMethod method, String defaultName) { 
     return convertForMethod(method, defaultName); 
    } 

    private String convertForField(String defaultName) { 
     return defaultName; 
    } 

    private String convertForMethod(AnnotatedMethod method, String defaultName) { 
     if (isGetter(method)) { 
      return method.getName().substring(3); 
     } 
     if (isSetter(method)) { 
      return method.getName().substring(3); 
     } 
     return defaultName; 
    } 

    private boolean isGetter(AnnotatedMethod method) { 
     if (Modifier.isPublic(method.getModifiers()) && method.getGenericParameterTypes().length == 0) { 
      if (method.getName().matches("^get[A-Z].*") && !method.getGenericReturnType().equals(void.class)) 
       return true; 
      if (method.getName().matches("^is[A-Z].*") && method.getGenericReturnType().equals(boolean.class)) 
       return true; 
     } 
     return false; 
    } 

    private boolean isSetter(AnnotatedMethod method) { 
     return Modifier.isPublic(method.getModifiers()) && method.getGenericReturnType().equals(void.class) && method.getGenericParameterTypes().length == 1 
       && method.getName().matches("^set[A-Z].*"); 
    } 

} 
+3

實現自定義['PropertyNamingStrategy'](https://github.com/FasterXML/jackson-databind/ blob/master/src/main/java/com/fasterxml/jackson/databind/PropertyNamingStrategy.java),也許 – 2014-11-04 21:30:39

+0

你是如何使用@JsonProperty的?你傳遞給它的字符串字段名稱? – 2014-11-04 21:45:03

+0

我沒有看到實現PropertyNamingStrategy以正確匹配字段名稱的方法。如果一個字段被命名爲「ABC」,另一個命名爲XYz,則在序列化/反序列化時,它們將不匹配JSON。 – MBarni 2014-11-05 10:50:20

回答

2

我認爲這是(使用定製PropertyNamingStrategy)解決方案:

import com.fasterxml.jackson.databind.PropertyNamingStrategy; 
import com.fasterxml.jackson.databind.cfg.MapperConfig; 
import com.fasterxml.jackson.databind.introspect.AnnotatedField; 
import com.fasterxml.jackson.databind.introspect.AnnotatedMethod; 

public class MyPropertyNamingStrategy extends PropertyNamingStrategy { 
    @Override 
    public String nameForField(MapperConfig<?> config, AnnotatedField field, String defaultName) { 
     return convert(field.getName()); 
    } 

    @Override 
    public String nameForGetterMethod(MapperConfig<?> config, AnnotatedMethod method, String defaultName) { 
     return convert(method.getName().toString()); 
    } 

    @Override 
    public String nameForSetterMethod(MapperConfig<?> config, AnnotatedMethod method, String defaultName) { 
     return convert(method.getName().toString()); 
    } 

    private String convert(String input) { 
     return input.substring(3); 
    } 
} 

測試

import com.fasterxml.jackson.databind.ObjectMapper; 
import com.fasterxml.jackson.databind.SerializationFeature; 

import java.io.IOException; 
import java.io.StringWriter; 

public class MyPropertyNamingStrategyTest { 
    public static void main(String[] args) { 
     PrivatePerson privatePerson = new PrivatePerson(); 
     privatePerson.setFirstName("John"); 
     privatePerson.setLastName("Smith"); 

     ObjectMapper mapper = new ObjectMapper(); 
     mapper.setPropertyNamingStrategy(new MyPropertyNamingStrategy()); 
     mapper.enable(SerializationFeature.INDENT_OUTPUT); 
     StringWriter sw = new StringWriter(); 
     try { 
      mapper.writeValue(sw, privatePerson); 
     } catch (IOException e) { 
      e.printStackTrace(); 
     } 
     System.out.println(sw.toString()); 
    } 
} 

PrivatePerson

public class PrivatePerson { 
    private String firstName; 
    private String lastName; 

    public void setFirstName(String firstName) { 
     this.firstName = firstName; 
    } 

    public String getFirstName() { 
     return firstName; 
    } 

    public void setLastName(String lastName) { 
     this.lastName = lastName; 
    } 

    public String getLastName() { 
     return lastName; 
    } 
} 
+0

現在這些字段都是大寫的。序列化和反序列化只有在類字段都是大寫的時纔有效。 – MBarni 2014-11-05 10:48:19

+0

您是否嘗試更改轉換方法以返回輸入?私人字符串轉換(字符串輸入){ return input; } – BlueLettuce16 2014-11-05 10:50:20

+0

是的,我做到了。不同之處在於,它們現在都是小型的。該案件從未受到尊重,或者它們都是Upper,Lower,或者Pascal(第一個字母大寫)......但僅僅尊重案件不是一個可以找到的選項。 – MBarni 2014-11-05 11:04:34

5

我已經有同樣的問題。

這是我的解決方案:

public class MyNamingStrategy extends PropertyNamingStrategy { 

    @Override 
    public String nameForField(MapperConfig<?> config, AnnotatedField field, String defaultName) { 
     return field.getName(); 
    } 

    @Override 
    public String nameForGetterMethod(MapperConfig<?> config, AnnotatedMethod method, String defaultName) { 
     return convert(method, defaultName); 
    } 

    @Override 
    public String nameForSetterMethod(MapperConfig<?> config, AnnotatedMethod method, String defaultName) { 
     return convert(method, defaultName); 
    } 

    private String convert(AnnotatedMethod method, String defaultName) { 

     Class<?> clazz = method.getDeclaringClass(); 
     List<Field> flds = FieldUtils.getAllFieldsList(clazz); 
     for (Field fld : flds) { 
      if (fld.getName().equalsIgnoreCase(defaultName)) { 
       return fld.getName(); 
      } 
     } 

     return defaultName; 
    } 
} 

在這種情況下,你會得到屬性的準確名稱,而不必依賴於方法的正確名稱。

1

可以配置傑克遜是大小寫寬容:

ObjectMapper mapper = new ObjectMapper(); 
mapper.configure(MapperFeature.ACCEPT_CASE_INSENSITIVE_PROPERTIES, true); 

CUDOS到https://stackoverflow.com/a/32842962/1639556

+0

將有助於序列化,或只是爲了反序列化? – eis 2017-06-28 07:04:07

+0

我試過這個反序列化傳入的請求。但對我來說這會影響序列化是沒有意義的。您已經擁有該對象,並且每次只能以某種方式序列化它。 – 2017-06-28 07:08:29

+0

事實上,它並不能解決OP所遇到的問題 - 他希望擁有用於序列化和反序列化的原始版本。 – eis 2017-06-28 07:10:23