2014-11-04 4 views
5

Когда я сериализую/десериализую любой объект, все имена полей преобразуются в нижний регистр. Есть ли какая-либо конфигурация, которая заставит Джексона сохранить имена полей точно так, как они есть? И для сериализации и десериализации?Проблемы с верхним/нижним регистром 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); 
    } 

} 

Спасибо to @ 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/quickxml/jackson/databind/PropertyNamingStrategy.java), возможно –

+0

Как вы используете @JsonProperty? Вы передаете ему имя поля String? –

+0

Я не вижу способа реализации PropertyNamingStrategy для правильного соответствия имен полей. Если поле называется «ABC», другое имя называется XYz, они не будут соответствовать JSON при сериализации/десериализации. – MBarni

ответ

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

+0

Вы пытались изменить в методе конвертации для возврата ввода? private String convert (String input) { return input; } – BlueLettuce16

+0

Да, я это сделал. Дифференциация заключается в том, что теперь они все нижние. Случай никогда не соблюдается, или все они верхние, все нижние или паскаль (первая буква в верхнем регистре) ... Но JUST RESPECING случай не является опцией. – MBarni

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

+0

Я попробовал это для десериализации входящего запроса. Но для меня нет никакого смысла, что это повлияет на сериализацию. У вас уже есть объект, и он должен быть сериализован только одним определенным способом каждый раз. –

+0

Действительно, поэтому он не решает проблему, с которой сталкивается OP - он хочет иметь оригинальные версии для сериализации и десериализации. – eis