【问题标题】:Jackson ObjectMapper upper/lower case issuesJackson ObjectMapper 大写/小写问题
【发布时间】:2014-11-04 20:57:12
【问题描述】:

当我序列化/反序列化任何对象时,所有字段名称都会转换为小写。 是否有任何配置可以让 Jackson 保持字段名称完全一样?用于序列化和反序列化?

(我知道@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].*");
    }

}

【问题讨论】:

  • 实现一个自定义的PropertyNamingStrategy,也许
  • 你如何使用@JsonProperty?您是否将字符串字段名称传递给它?
  • 我看不到实现 PropertyNamingStrategy 以正确匹配字段名称的方法。如果一个字段命名为“ABC”,另一个字段命名为XYz,在序列化/反序列化时它们将不匹配JSON。

标签: java json jackson


【解决方案1】:

即使@JsonProperty 不起作用,我也可以使用@JsonSetter@JsonGetter 来映射大写的json 字段名称。

@JsonSetter("ABC")
public void setABC(String ABC) {
    this.ABC= ABC;
}

Spring 现在会将对象字段序列化为“ABC”而不是“abc”。

【讨论】:

    【解决方案2】:

    我也遇到了同样的问题。

    这是我的解决方案:

    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;
        }
    }
    

    在这种情况下,您将获得属性的确切名称,而不必依赖于方法的正确名称。

    【讨论】:

    【解决方案3】:

    我认为这是解决方案(使用自定义 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());
        }
    }
    

    私人的

    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;
        }
    }
    

    【讨论】:

    • 现在这些字段都是大写的。仅当类字段全部大写时,序列化和反序列化才会起作用。
    • 您是否尝试更改转换方法以返回输入?私有字符串转换(字符串输入){返回输入; }
    • 是的,我做到了。不同之处在于它们现在都是小写的。大小写永远不会受到尊重,或者它们都是大写字母、小写字母或帕斯卡(第一个字母大写)......但只是尊重大小写不是一个选项。
    • 我找到了解决方案并编辑了代码。我更改了从 nameForField、nameForGetterMethod 和 nameForSetterMethod 返回的内容。
    • 我已经测试了你的课程,我收到了 from object to json: { "Test" : "1", "ABC" : "2", "XyZ" : "3" } 和来自 json反对:Example{Test='0', ABC='1', XyZ='2'} 你期望什么?如果您期望相同并且结果不同,那么您没有复制最新的解决方案。
    【解决方案4】:

    您可以将 Jackson 配置为区分大小写:

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

    感谢https://stackoverflow.com/a/32842962/1639556

    【讨论】:

    • 这将有助于序列化还是仅用于反序列化?
    • 我试过这个来反序列化传入的请求。但对我来说它会影响序列化是没有意义的。您已经拥有该对象,并且每次只能以一种特定方式对其进行序列化。
    • 确实如此,所以它并不能解决 OP 遇到的问题 - 他希望拥有用于序列化和反序列化的原始版本。
    • 你说得对,我错过了那部分。无论如何,我的回答将来可能对谷歌人有所帮助。我发现它比其他解决方案更早。
    【解决方案5】:

    使用@JsonProperty 注解。效果很好

    例子

    @JsonProperty("Code")
    private String Code;
    @JsonProperty("Message")
    private String Message;
    

    【讨论】:

      【解决方案6】:

      为 PropertyNamingStrategy 创建了一个自己的类-根据答案 7 工作正常

      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);
          }
      }
      

      我有我的 POJO 类 - Payload 类:

      package orderCreateAPI;
              
      import java.util.ArrayList;
              
      public class Payload {
          OrderInfo OrderInfo;
                  
          ArrayList<orderCreateAPI.ShipmentInfo> ShipmentInfo;
                  
          public Payload(OrderInfo order, ArrayList<orderCreateAPI.ShipmentInfo> shipInfo){
                      
              this.OrderInfo =order;
              this.ShipmentInfo = shipInfo;
          }
              
          public OrderInfo getOrderInfo() {
              return OrderInfo;
          }
              
          public void setOrderInfo(OrderInfo orderInfo) {
              OrderInfo = orderInfo;
          }
              
          public ArrayList<orderCreateAPI.ShipmentInfo> getShipmentInfo() {
              return ShipmentInfo;
          }
              
          public void setShipmentInfo(ArrayList<orderCreateAPI.ShipmentInfo> shipmentInfo) {
              ShipmentInfo = shipmentInfo;
          }
              
      }
      

      执行类:

      public class TC1_CreateOrder extends orderCreateRequest{
          @Test
          public static void TC1_CreateOrder() throws JsonProcessingException,JsonMappingException,IOException {
              //throws JsonParseException,JsonMappingException,IOException
              //Data fetch
              ArrayList<OrderReferences> orRef = new ArrayList<OrderReferences>();
              orRef.add(new OrderReferences("BM","IFC"));
              ArrayList<OrderItem> orItem = new ArrayList<OrderItem>();
              orItem.add(new OrderItem("AOTEST1001","60111"));
              ShipperInfo ship = new ShipperInfo("URBN","URBN PA DC");
              ArrayList<ShipmentInfo> ShipInfo = new ArrayList<ShipmentInfo>();
              ShipInfo.add(new ShipmentInfo("ASTEST1001","RCVD"),ship, orItem));
              ConsigneeInfo ConsigneeInfo = new ConsigneeInfo("Green Mile","133 Avenue");  
              OrderInfo OrderInfo = new OrderInfo("AOTEST1001", "2021-09-03T",orRef, ConsigneeInfo);
              Payload p = new Payload(OrderInfo,ShipInfo);
              ObjectMapper mapper = new ObjectMapper();
              mapper.setPropertyNamingStrategy(new MyPropertyNamingStrategy());
                      
              StringWriter s = new StringWriter();
              try {
                  mapper.writeValue(s, p);
              } catch (IOException e) {
                  e.printStackTrace();
              }                
          }
      }
      

      之前的响应正文:-错误的属性

      {
          "orderInfo": {
              "orderNumber": "AOTEST1010",
              "orderCreatedDate": "2021-09-03T00:00:00.000Z"
          }
      }
      

      响应正文之后:-正确的属性

      {
          "OrderInfo": {
              "OrderNumber": "AOTEST1010",
              "OrderCreatedDate": "2021-09-03T00:00:00.000Z"
          }
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2010-11-18
        • 2019-11-25
        • 1970-01-01
        • 2013-02-24
        • 1970-01-01
        相关资源
        最近更新 更多