【问题标题】:ObjectMapper properties set in a generic way?以通用方式设置 ObjectMapper 属性?
【发布时间】:2016-01-11 07:21:11
【问题描述】:

我正在编写一个类JsonUtils,它将包含不同的函数来序列化和反序列化数据。

 public class JsonUtils {

        private static final ObjectMapper JSON_MAPPER = new ObjectMapper();

        public static String toJsonString(Object obj)  {

            String json = null;

            JSON_MAPPER.setPropertyNamingStrategy(new CustomNamingStrategy());
            JSON_MAPPER.setSerializationInclusion(Inclusion.NON_NULL);

            try {
                System.out.print("OBJECT MAPPER:---> JSON STRING:\n" + JSON_MAPPER.writerWithDefaultPrettyPrinter().writeValueAsString(obj));
                json = JSON_MAPPER.writerWithDefaultPrettyPrinter().writeValueAsString(obj);
            } catch (JsonGenerationException e) {
                e.printStackTrace();
            } catch (JsonMappingException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
            return json;
        }

        public static <T> T toPOJO(String json, Class<T> type){

            JSON_MAPPER.setPropertyNamingStrategy(new CustomNameNamingStrategy());
            System.out.println("TO POJO: Json string " + json);
            try {

                return JSON_MAPPER.readValue(json, type);

            } catch (JsonParseException e) {
                e.printStackTrace();
            } catch (JsonMappingException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
            return null;
        }

现在,我希望通用地使用这些函数。例如:有人想调用toJsonString 方法,但想使用不同的命名策略来转换为 json。或者可能想向ObjectMapper 添加一些其他属性,例如注册一个模块。

目前,ObjectMapper 属性正在函数内部设置,因此无法使用新的命名策略或 ObjectMapper 的不同属性。

有没有办法让JsonUtils 的每个用户最初都为ObjectMapper 设置自己的属性?还是一种高效且通用的方式来编写我的 Utility 类?

【问题讨论】:

  • 您可以使用杰克逊对象映射器,因为它可以方便您进行所需的操作。
  • @AtaurRahmanMunna:我正在使用 jackson ObjectMapper 本身。你指的是哪个对象映射器?

标签: java json jackson objectmapper


【解决方案1】:

你可以使用这样的东西:

ObjectMapperProperties.java

package example;
import com.fasterxml.jackson.databind.PropertyNamingStrategy;

        public class ObjectMapperProperties {

            private PropertyNamingStrategy propertyNamingStrategy;

            private ObjectMapperProperties(final PropertyNamingStrategy propertyNamingStrategy) {
                this.propertyNamingStrategy = propertyNamingStrategy;
            }

            public PropertyNamingStrategy getPropertyNamingStrategy() {
                return propertyNamingStrategy;
            }

            public static class ObjectMapperPropertiesBuilder {

                private PropertyNamingStrategy builderPropertyNamingStrategy;

                public ObjectMapperPropertiesBuilder() {

                }

                public ObjectMapperPropertiesBuilder setPropertyNamingStrategy(final PropertyNamingStrategy builderPropertyNamingStrategy) {
                    this.builderPropertyNamingStrategy = builderPropertyNamingStrategy; 
                    return this;
                }

                public ObjectMapperProperties build() {
                    return new ObjectMapperProperties(builderPropertyNamingStrategy);
                }

            }
    }

ObjectMapperFactory.java

package example;
import com.fasterxml.jackson.databind.ObjectMapper;

public class ObjectMapperFactory {

    public static ObjectMapper getObjectMapper(final ObjectMapperProperties objectMapperProperties) {
        final ObjectMapper result = new ObjectMapper();
        result.setPropertyNamingStrategy(objectMapperProperties.getPropertyNamingStrategy());
        return result;
    }

}

客户端.class

package example;

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

import example.ObjectMapperProperties.ObjectMapperPropertiesBuilder;

public class Client {

    public static void main(String[] args) {
        ObjectMapperPropertiesBuilder objectMapperPropertiesBuilder = new ObjectMapperPropertiesBuilder();
        objectMapperPropertiesBuilder.setPropertyNamingStrategy(PropertyNamingStrategy.CAMEL_CASE_TO_LOWER_CASE_WITH_UNDERSCORES);
        ObjectMapperFactory factory = new ObjectMapperFactory();
        ObjectMapper objectMapper = ObjectMapperFactory.getObjectMapper(objectMapperPropertiesBuilder.build());

    }

}

您可以根据需要使用设置创建 ObjectMapper。在已经创建的实例上设置两次属性没有意义,而且容易出错。

private static final ObjectMapper JSON_MAPPER = new ObjectMapper();
JSON_MAPPER.setSerializationInclusion(Inclusion.NON_NULL);

所以下次你需要重新设置这个属性时,但是通过一些工厂创建新的 ObjectMapper() 是无价的并且不易出错

答案:

不,您将通过 ObjectMapperFactory 为每次调用创建新的 ObjectMapper 实例,并且只需传递 ObjectMapperProperties。

public static String toJsonString(Object obj,final ObjectMapperProperties objectMapperProperties)  {

ObjectMapper objectMapper = ObjectMapperFactory.getObjectMapper(objectMapperProperties);
}

如果您不想创建新的 ObjectMapper 实例并且属性是最终的(意味着您将始终创建具有相同属性的 ObjectMapper)而不是创建一个方法。

public static String toJsonString(Object obj, ObjectMapper objMapper)  {}

第二个问题见Builder Pattern

为了更好地测试以工厂为接口的变体将有所帮助:

ObjectMapperFactory.class

public interface ObjectMapperFactory {

    public ObjectMapper getObjectMapper(final ObjectMapperProperties objectMapperProperties) {
}

ObjectMapperFactory的实现

ObjectMapperFactoryImpl.class

package example;
import com.fasterxml.jackson.databind.ObjectMapper;

public class ObjectMapperFactoryImpl implements ObjectMapperFactory {

    public ObjectMapper getObjectMapper(final ObjectMapperProperties objectMapperProperties) {
        final ObjectMapper result = new ObjectMapper();
        result.setPropertyNamingStrategy(objectMapperProperties.getPropertyNamingStrategy());
        return result;
    }

}

在你的班级里

 public class JsonUtils {

      private final ObjectMapperFactory objectMapperFactory;

      public JsonUtils(final ObjectMapperFactory objectMapperFactory) {
              this.objectMapperFactory = objectMapperFactory;
      }
}

但这只是一个变体。出于您的目的,上面发布的答案就足够了。

【讨论】:

  • 所以在每个函数中我都必须传递 objectmapper 实例?
  • 这里要添加属性,我必须在ObjectMapperPropertiesObjectMapperPropertiesBuilder 中都添加它。这不是重复吗?
【解决方案2】:

您可以使用 hashmap 并在调用之前,从调用者函数中首先输入一些这样的设置值

Map <String, String>settings = new HashMap<String, String>();
        settings.put("CUSTOM_NAMING_PROPERTY", "CAMEL_CASE");

在您的函数toJsonString 中检查值。

    public static String toJsonString(Object obj,Map settings )  {

                String json = null;
                if(settings.get("CUSTOM_NAMING_PROPERTY")!=null){
                    //put your settings here.......
                }
                /////....... contd.....

                JSON_MAPPER.setSerializationInclusion(Inclusion.NON_NULL);

                try {
                    System.out.print("OBJECT MAPPER:---> JSON STRING:\n" + JSON_MAPPER.writerWithDefaultPrettyPrinter().writeValueAsString(obj));
                    json = JSON_MAPPER.writerWithDefaultPrettyPrinter().writeValueAsString(obj);
                } catch (JsonGenerationException e) {
                    e.printStackTrace();
                } catch (JsonMappingException e) {
                    e.printStackTrace();
                } catch (IOException e) {
                    e.printStackTrace();
                }
                return json;
            }

【讨论】:

  • ObjectMapper中有多个属性,比如可以注册一个模块来添加JsonSerailizer,这样会导致函数有多个参数。所以这会导致函数的很多参数
  • 让我们添加一个 hashmap 作为参数,这可能会有所帮助。
  • ObjectMapper 实例传递给每个函数是个好主意吗?所以函数的每个调用者都会根据自己的需要初始化ObjectMapper
猜你喜欢
  • 1970-01-01
  • 2012-08-20
  • 2017-08-05
  • 2021-06-22
  • 1970-01-01
  • 1970-01-01
  • 2023-01-03
  • 1970-01-01
  • 2019-06-25
相关资源
最近更新 更多