Java ObjectMapper的使用和使用过程中遇到的问题

 更新时间:2024年07月04日 10:49:23   作者:Alex_81D  
在Java开发中,ObjectMapper是Jackson库的核心类,用于将Java对象序列化为JSON字符串,或者将JSON字符串反序列化为Java对象,这篇文章主要介绍了Java ObjectMapper的使用和使用过程中遇到的问题,需要的朋友可以参考下

背景:

在Java开发中,ObjectMapper是Jackson库的核心类,用于将Java对象序列化为JSON字符串,或者将JSON字符串反序列化为Java对象。由于其功能强大且易于使用,ObjectMapper成为了处理JSON数据的常用工具,它可以帮助我们快速的进行各个类型和Json类型的相互转换。然而,在实际开发中,很多开发者可能会犯一个常见的错误:频繁地创建ObjectMapper实例

先说一下我们代码使用中发现的一些习惯案例:

一、ObjectMapper的使用

1.引入Jackson的依赖

<!-- 根据自己需要引入相关版本依赖。 -->
<dependency>
  <groupId>com.fasterxml.jackson.core</groupId>
  <artifactId>jackson-core</artifactId>
  <version>2.9.10</version>
</dependency>
<dependency>
  <groupId>com.fasterxml.jackson.core</groupId>
  <artifactId>jackson-databind</artifactId>
  <version>2.9.10</version>
</dependency>
<dependency>
  <groupId>com.fasterxml.jackson.core</groupId>
  <artifactId>jackson-annotations</artifactId>
  <version>2.9.10</version>
</dependency>

2. ObjectMapper的常用配置

private static final ObjectMapper mapper;
public static ObjectMapper getObjectMapper(){
    return this.mapper;
}
static{
    //创建ObjectMapper对象
    mapper = new ObjectMapper()
    //configure方法 配置一些需要的参数
    // 转换为格式化的json 显示出来的格式美化
    mapper.enable(SerializationFeature.INDENT_OUTPUT);
   //序列化的时候序列对象的那些属性  
   //JsonInclude.Include.NON_DEFAULT 属性为默认值不序列化 
   //JsonInclude.Include.ALWAYS      所有属性
   //JsonInclude.Include.NON_EMPTY   属性为 空(“”) 或者为 NULL 都不序列化 
   //JsonInclude.Include.NON_NULL    属性为NULL 不序列化
   mapper.setSerializationInclusion(JsonInclude.Include.ALWAYS);  
    //反序列化时,遇到未知属性会不会报错 
    //true - 遇到没有的属性就报错 false - 没有的属性不会管,不会报错
    mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
    //如果是空对象的时候,不抛异常  
    mapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);  
    // 忽略 transient 修饰的属性
    mapper.configure(MapperFeature.PROPAGATE_TRANSIENT_MARKER, true);
    //修改序列化后日期格式
    mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);  
    mapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
   //处理不同的时区偏移格式
   mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
   mapper.registerModule(new JavaTimeModule());
}

3.ObjectMapper的常用方法

3.1 json字符串转对象

ObjectMapper mapper = new ObjectMapper();
String jsonString = "{\"name\":\"Hyl\", \"age\":20}";
//将字符串转换为对象
Student student = mapper.readValue(jsonString, Student.class);
System.out.println(student);
//将对象转换为json字符串
jsonString = mapper.writeValueAsString(student);
System.out.println(jsonString);
结果:
Student [ name: Hyl, age: 20 ]
{
  "name" : "Hyl",
  "age" : 20
}

3.2 数组和对象之间转换

//对象转为byte数组
byte[] byteArr = mapper.writeValueAsBytes(student);
System.out.println(byteArr);
//byte数组转为对象
Student student= mapper.readValue(byteArr, Student.class);
System.out.println(student);
结果:
[B@3327bd23
Student [ name: Hyl, age: 20 ]

3.3 集合和json字符串之间转换

List<Student> studentList= new ArrayList<>();
studentList.add(new Student("hyl1" ,20 , new Date()));
studentList.add(new Student("hyl2" ,21 , new Date()));
studentList.add(new Student("hyl3" ,22 , new Date()));
studentList.add(new Student("hyl4" ,23 , new Date()));
String jsonStr = mapper.writeValueAsString(studentList);
System.out.println(jsonStr);
List<Student> studentList2 = mapper.readValue(jsonStr, List.class);
System.out.println("字符串转集合:" + studentList2 );
结果:
[ {
  "name" : "hyl1",
  "age" : 20,
  "sendTime" : 1525164212803
}, {
  "name" : "hyl2",
  "age" : 21,
  "sendTime" : 1525164212803
}, {
  "name" : "hyl3",
  "age" : 22,
  "sendTime" : 1525164212803
}, {
  "name" : "hyl4",
  "age" : 23,
  "sendTime" : 1525164212803
} ]
[{name=hyl1, age=20, sendTime=1525164212803}, {name=hyl2, age=21, sendTime=1525164212803}, {name=hyl3, age=22, sendTime=1525164212803}, {name=hyl4, age=23, sendTime=1525164212803}]

3.4 map和json字符串之间转换

Map<String, Object> testMap = new HashMap<>();
testMap.put("name", "22");
testMap.put("age", 20);
testMap.put("date", new Date());
testMap.put("student", new Student("hyl", 20, new Date()));
String jsonStr = mapper.writeValueAsString(testMap);
System.out.println(jsonStr);
Map<String, Object> testMapDes = mapper.readValue(jsonStr, Map.class);
System.out.println(testMapDes);
结果:
{
  "date" : 1525164212803,
  "name" : "22",
  "student" : {
    "name" : "hyl",
    "age" : 20,
    "sendTime" : 1525164212803,
    "intList" : null
  },
  "age" : 20
}
{date=1525164212803, name=22, student={name=hyl, age=20, sendTime=1525164212803, intList=null}, age=20}

3.5 日期转json字符串

// 修改时间格式
mapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
Student student = new Student ("hyl",21, new Date());
student.setIntList(Arrays.asList(1, 2, 3));
String jsonStr = mapper.writeValueAsString(student);
System.out.println(jsonStr);
结果:
{
  "name" : "hyl",
  "age" : 21,
  "sendTime" : "2020-07-23 13:14:36",
  "intList" : [ 1, 2, 3 ]
}

3.6 js中将字符串转换为json对象

var data = "{\"name\":\"Hyl\", \"age\":20}";
var student = eval(data);
console.info(student.name);
console.info(student.age);
结果:
Hyl
20

https://www.jb51.net/program/32374191h.htm

二、频繁地创建ObjectMapper实例带来的思考:

这种做法不仅会降低程序的性能,还可能引发一些难以察觉的问题。因为每次创建ObjectMapper实例时,都需要消耗一定的内存和计算资源。如果频繁创建实例,这些资源的消耗会迅速积累,最终影响程序的性能和稳定性。

那么,如何高效地使用ObjectMapper呢?答案是尽可能地复用ObjectMapper实例。下面是一些建议:

1.单例模式 单例模式:将ObjectMapper实例作为单例对象管理,确保整个应用程序中只有一个实例。这样可以避免重复创建实例,减少资源消耗。可以使用Java的单例模式来实现这一点,例如:

public class ObjectMapperHolder {
    private static final ObjectMapper objectMapper = new ObjectMapper();
    public static ObjectMapper getObjectMapper() {
        return objectMapper;
    }
}

在需要使用ObjectMapper的地方,可以通过 ObjectMapperHolder.getObjectMapper() 来获取实例。

  • 配置共享:如果应用程序中有多个模块或组件需要使用ObjectMapper,可以考虑将这些模块或组件的ObjectMapper配置统一到一个共享的配置文件中。这样,每个模块或组件都可以使用相同的ObjectMapper实例,避免了重复创建。
  • 线程安全:由于ObjectMapper实例是复用的,因此需要确保它是线程安全的。Jackson库已经为我们处理了这个问题,ObjectMapper实例本身是线程安全的。但是,如果我们在ObjectMapper上注册了自定义的序列化器或反序列化器,那么这些自定义组件可能需要额外的线程安全措施。

2.优化建议

除了避免频繁创建ObjectMapper实例外,还有一些其他的优化建议:

  • 启用缓存:ObjectMapper提供了一些缓存机制,如属性访问器缓存和类型缓存。通过启用这些缓存,可以提高序列化和反序列化的性能。
  • 自定义序列化器和反序列化器:对于特殊的Java类型或复杂的JSON结构,可以编写自定义的序列化器和反序列化器。这不仅可以提高性能,还可以使代码更加清晰和易于维护。
  • 调整日期格式:在序列化日期类型的Java对象时,可以通过设置ObjectMapper的日期格式来避免生成冗长的日期字符串。这可以减小JSON字符串的大小,提高传输和解析的效率。

总之,高效地使用ObjectMapper可以避免不必要的性能损耗和潜在的问题。通过复用ObjectMapper实例、配置共享、确保线程安全以及采用其他优化措施,我们可以充分发挥ObjectMapper的强大功能,提高Java应用程序的性能和稳定性。

https://developer.baidu.com/article/details/3233714

三、附:JSONUtils的部分方法:

import com.fasterxml.jackson.annotation.JsonInclude.Include;
import com.fasterxml.jackson.core.JsonGenerationException;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.*;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.TimeZone;
/**
 * Json utils
 */
@SuppressWarnings("deprecation")
public class JsonUtils {
    private static final ObjectMapper objectMapper;
    private static Logger logger = LoggerUtil.getLogger();
    static {
        objectMapper = new ObjectMapper();
        // Remove the default timestamp format
        objectMapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
        // Set to Shanghai time zone in China
        objectMapper.setTimeZone(TimeZone.getTimeZone("GMT+8"));
        objectMapper.configure(SerializationFeature.WRITE_NULL_MAP_VALUES, false);
        // Null value not serialized
        objectMapper.setSerializationInclusion(Include.NON_NULL);
        // Compatible processing when attributes are not present during deserialization
        objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        // Uniform format of dates when serializing
        objectMapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
        // It is forbidden to deserialize "Enum" with "int" on behalf of "Enum"
        objectMapper.configure(DeserializationFeature.FAIL_ON_NUMBERS_FOR_ENUMS, true);
        objectMapper.configure(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY, true);
        // objectMapper.configure(DeserializationFeature.USE_JAVA_ARRAY_FOR_JSON_ARRAY,
        // true);
        objectMapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
        // Single quote processing
        objectMapper.configure(com.fasterxml.jackson.core.JsonParser.Feature.ALLOW_SINGLE_QUOTES, true);
        // objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.OBJECT_AND_NON_CONCRETE);
    }
    public static ObjectMapper getObjectMapper() {
        return objectMapper;
    }
    public static <T> T toObjectNoException(String json, Class<T> clazz) {
        try {
            return objectMapper.readValue(json, clazz);
        } catch (JsonParseException e) {
            logger.error(e.getMessage(), e);
        } catch (JsonMappingException e) {
            logger.error(e.getMessage(), e);
        } catch (IOException e) {
            logger.error(e.getMessage(), e);
        }
        return null;
    }
    public static <T> String toJsonNoException(T entity) {
        try {
            return objectMapper.writeValueAsString(entity);
        } catch (JsonGenerationException e) {
            logger.error(e.getMessage(), e);
        } catch (JsonMappingException e) {
            logger.error(e.getMessage(), e);
        } catch (IOException e) {
            logger.error(e.getMessage(), e);
        }
        return null;
    }
    public static <T> String toFormatJsonNoException(T entity) {
        try {
            return objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(entity);
        } catch (JsonGenerationException e) {
            logger.error(e.getMessage(), e);
        } catch (JsonMappingException e) {
            logger.error(e.getMessage(), e);
        } catch (IOException e) {
            logger.error(e.getMessage(), e);
        }
        return null;
    }
    public static <T> T toCollectionNoException(String json, TypeReference<T> typeReference) {
        try {
            return objectMapper.readValue(json, typeReference);
        } catch (JsonParseException e) {
            logger.error(e.getMessage(), e);
        } catch (JsonMappingException e) {
            logger.error(e.getMessage(), e);
        } catch (IOException e) {
            logger.error(e.getMessage(), e);
        }
        return null;
    }
    public static String toString(Object object) throws JsonProcessingException {
        return objectMapper.writeValueAsString(object);
    }
    public static <T> T toObject(String jsonString, Class<T> rspValueType)
            throws JsonParseException, JsonMappingException, IOException {
        return objectMapper.readValue(jsonString, rspValueType);
    }
    public static JsonNode readJsonNode(String jsonStr, String fieldName) {
        if (StringUtils.isEmpty(jsonStr)) {
            return null;
        }
        try {
            JsonNode root = objectMapper.readTree(jsonStr);
            return root.get(fieldName);
        } catch (IOException e) {
            logger.error("parse json string error:" + jsonStr, e);
            return null;
        }
    }
    @SuppressWarnings("unchecked")
    public static <T> T readJson(JsonNode node, Class<?> parametrized, Class<?>... parameterClasses) throws Exception {
        JavaType javaType = objectMapper.getTypeFactory().constructParametricType(parametrized, parameterClasses);
        return (T) objectMapper.readValue(toString(node), javaType);
    }
    public class CustomDateSerializer extends JsonSerializer<Date> {
        @Override
        public void serialize(Date value, JsonGenerator jgen, SerializerProvider provider)
                throws IOException, JsonProcessingException {
            SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd");
            String formattedDate = formatter.format(value);
            jgen.writeString(formattedDate);
        }
    }
}

到此这篇关于Java ObjectMapper的使用和使用过程中遇到的问题的文章就介绍到这了,更多相关Java ObjectMapper使用内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Java使用JaCoCo进行代码覆盖率分析的操作指南

    Java使用JaCoCo进行代码覆盖率分析的操作指南

    JaCoCo是一个开源的 Java 代码覆盖率工具,广泛应用于测试过程中,它可以帮助开发者分析测试代码的覆盖情况,在本文中,我们将介绍 JaCoCo 的基本功能、如何集成到 Maven 项目中,以及通过具体案例展示如何生成覆盖率报告,需要的朋友可以参考下
    2025-02-02
  • 详解Spring如何解析占位符

    详解Spring如何解析占位符

    Spring一直支持将属性定义到外部的属性的文件中,并使用占占位符的形式为使用"${}"包装的属性名称,为了使用属性占位符,我们必须配置一个PropertyPlaceholderConfigurer或PropertySourcesPlaceholderConfigurer实例,本文将介绍如何解析占位符
    2021-06-06
  • Java读取寄存器数据的方法示例详解

    Java读取寄存器数据的方法示例详解

    在Java中读取硬件寄存器数据不直接支持,但可以通过JNI或JNA技术实现,此过程需要编写本地代码(如C/C++)以模拟硬件交互,然后在Java中调用这些方法,注意,JNI使用可能引入复杂性和性能开销,且需考虑跨平台兼容性,感兴趣的朋友跟随小编一起看看吧
    2024-09-09
  • SpringBoot配置MySQL5.7与MySQL8.0的异同点详解

    SpringBoot配置MySQL5.7与MySQL8.0的异同点详解

    MySQL 是 Java 开发中最常用的数据库之一,而 Spring Boot 提供了便捷的配置方式,随着 MySQL 8.0 的普及,许多开发者需要从 MySQL 5.7 升级到 8.0,在实际开发中,二者的配置方式既有相似之处,也有一些需要特别注意的不同点,所以本文给大家详细介绍了它们的异同点
    2024-12-12
  • springboot整合xxl-job的实现示例

    springboot整合xxl-job的实现示例

    本文主要介绍了springboot整合xxl-job的实现示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-06-06
  • Springboot2.6.x的启动流程与自动配置详解

    Springboot2.6.x的启动流程与自动配置详解

    这篇文章主要给大家介绍了关于Springboot2.6.x的启动流程与自动配置的相关资料,文中通过实例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2022-01-01
  • Java并发框架中的AQS详细解析

    Java并发框架中的AQS详细解析

    这篇文章主要介绍了Java并发框架中的AQS详细解析,之前说锁的升级的时候,说到了自旋锁会空转几次尝试等待获取资源,其实这一系列的动作是有一个规范的这个规范叫做同步发生器AbstractQueuedSynchronizer ,简称AQS,需要的朋友可以参考下
    2024-01-01
  • springboot后端解决跨域问题

    springboot后端解决跨域问题

    今天小编就为大家分享一篇关于springboot后端解决跨域问题,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来看看吧
    2019-03-03
  • SpringCloud Feign客户端使用流程

    SpringCloud Feign客户端使用流程

    在springcloud中,openfeign是取代了feign作为负载均衡组件的,feign最早是netflix提供的,他是一个轻量级的支持RESTful的http服务调用框架,内置了ribbon,而ribbon可以提供负载均衡机制,因此feign可以作为一个负载均衡的远程服务调用框架使用
    2023-01-01
  • 深入了解Java核心类库--Math类

    深入了解Java核心类库--Math类

    本文是小编最新给大家整理的关于Java中Math类常用方法的知识,通过实例代码给大家介绍的非常详细,感兴趣的朋友一起看看吧,
    2021-07-07

最新评论