Java?ObjectMapper的使用和使用過程中遇到的問題
背景:
在Java開發(fā)中,ObjectMapper是Jackson庫的核心類,用于將Java對(duì)象序列化為JSON字符串,或者將JSON字符串反序列化為Java對(duì)象。由于其功能強(qiáng)大且易于使用,ObjectMapper成為了處理JSON數(shù)據(jù)的常用工具,它可以幫助我們快速的進(jìn)行各個(gè)類型和Json類型的相互轉(zhuǎn)換。然而,在實(shí)際開發(fā)中,很多開發(fā)者可能會(huì)犯一個(gè)常見的錯(cuò)誤:頻繁地創(chuàng)建ObjectMapper實(shí)例。
先說一下我們代碼使用中發(fā)現(xiàn)的一些習(xí)慣案例:
一、ObjectMapper的使用
1.引入Jackson的依賴
<!-- 根據(jù)自己需要引入相關(guān)版本依賴。 --> <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{ //創(chuàng)建ObjectMapper對(duì)象 mapper = new ObjectMapper() //configure方法 配置一些需要的參數(shù) // 轉(zhuǎn)換為格式化的json 顯示出來的格式美化 mapper.enable(SerializationFeature.INDENT_OUTPUT); //序列化的時(shí)候序列對(duì)象的那些屬性 //JsonInclude.Include.NON_DEFAULT 屬性為默認(rèn)值不序列化 //JsonInclude.Include.ALWAYS 所有屬性 //JsonInclude.Include.NON_EMPTY 屬性為 空(“”) 或者為 NULL 都不序列化 //JsonInclude.Include.NON_NULL 屬性為NULL 不序列化 mapper.setSerializationInclusion(JsonInclude.Include.ALWAYS); //反序列化時(shí),遇到未知屬性會(huì)不會(huì)報(bào)錯(cuò) //true - 遇到?jīng)]有的屬性就報(bào)錯(cuò) false - 沒有的屬性不會(huì)管,不會(huì)報(bào)錯(cuò) mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); //如果是空對(duì)象的時(shí)候,不拋異常 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")); //處理不同的時(shí)區(qū)偏移格式 mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS); mapper.registerModule(new JavaTimeModule()); }
3.ObjectMapper的常用方法
3.1 json字符串轉(zhuǎn)對(duì)象
ObjectMapper mapper = new ObjectMapper(); String jsonString = "{\"name\":\"Hyl\", \"age\":20}"; //將字符串轉(zhuǎn)換為對(duì)象 Student student = mapper.readValue(jsonString, Student.class); System.out.println(student); //將對(duì)象轉(zhuǎn)換為json字符串 jsonString = mapper.writeValueAsString(student); System.out.println(jsonString); 結(jié)果: Student [ name: Hyl, age: 20 ] { "name" : "Hyl", "age" : 20 }
3.2 數(shù)組和對(duì)象之間轉(zhuǎn)換
//對(duì)象轉(zhuǎn)為byte數(shù)組 byte[] byteArr = mapper.writeValueAsBytes(student); System.out.println(byteArr); //byte數(shù)組轉(zhuǎn)為對(duì)象 Student student= mapper.readValue(byteArr, Student.class); System.out.println(student); 結(jié)果: [B@3327bd23 Student [ name: Hyl, age: 20 ]
3.3 集合和json字符串之間轉(zhuǎn)換
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("字符串轉(zhuǎn)集合:" + studentList2 ); 結(jié)果: [ { "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字符串之間轉(zhuǎn)換
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); 結(jié)果: { "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 日期轉(zhuǎn)json字符串
// 修改時(shí)間格式 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); 結(jié)果: { "name" : "hyl", "age" : 21, "sendTime" : "2020-07-23 13:14:36", "intList" : [ 1, 2, 3 ] }
3.6 js中將字符串轉(zhuǎn)換為json對(duì)象
var data = "{\"name\":\"Hyl\", \"age\":20}"; var student = eval(data); console.info(student.name); console.info(student.age); 結(jié)果: Hyl 20
http://www.dbjr.com.cn/program/32374191h.htm
二、頻繁地創(chuàng)建ObjectMapper實(shí)例帶來的思考:
這種做法不僅會(huì)降低程序的性能,還可能引發(fā)一些難以察覺的問題。因?yàn)槊看蝿?chuàng)建ObjectMapper實(shí)例時(shí),都需要消耗一定的內(nèi)存和計(jì)算資源。如果頻繁創(chuàng)建實(shí)例,這些資源的消耗會(huì)迅速積累,最終影響程序的性能和穩(wěn)定性。
那么,如何高效地使用ObjectMapper呢?答案是盡可能地復(fù)用ObjectMapper實(shí)例。下面是一些建議:
1.單例模式 單例模式:將ObjectMapper實(shí)例作為單例對(duì)象管理,確保整個(gè)應(yīng)用程序中只有一個(gè)實(shí)例。這樣可以避免重復(fù)創(chuàng)建實(shí)例,減少資源消耗??梢允褂肑ava的單例模式來實(shí)現(xiàn)這一點(diǎn),例如:
public class ObjectMapperHolder { private static final ObjectMapper objectMapper = new ObjectMapper(); public static ObjectMapper getObjectMapper() { return objectMapper; } }
在需要使用ObjectMapper的地方,可以通過 ObjectMapperHolder.getObjectMapper()
來獲取實(shí)例。
- 配置共享:如果應(yīng)用程序中有多個(gè)模塊或組件需要使用ObjectMapper,可以考慮將這些模塊或組件的ObjectMapper配置統(tǒng)一到一個(gè)共享的配置文件中。這樣,每個(gè)模塊或組件都可以使用相同的ObjectMapper實(shí)例,避免了重復(fù)創(chuàng)建。
- 線程安全:由于ObjectMapper實(shí)例是復(fù)用的,因此需要確保它是線程安全的。Jackson庫已經(jīng)為我們處理了這個(gè)問題,ObjectMapper實(shí)例本身是線程安全的。但是,如果我們在ObjectMapper上注冊了自定義的序列化器或反序列化器,那么這些自定義組件可能需要額外的線程安全措施。
2.優(yōu)化建議
除了避免頻繁創(chuàng)建ObjectMapper實(shí)例外,還有一些其他的優(yōu)化建議:
- 啟用緩存:ObjectMapper提供了一些緩存機(jī)制,如屬性訪問器緩存和類型緩存。通過啟用這些緩存,可以提高序列化和反序列化的性能。
- 自定義序列化器和反序列化器:對(duì)于特殊的Java類型或復(fù)雜的JSON結(jié)構(gòu),可以編寫自定義的序列化器和反序列化器。這不僅可以提高性能,還可以使代碼更加清晰和易于維護(hù)。
- 調(diào)整日期格式:在序列化日期類型的Java對(duì)象時(shí),可以通過設(shè)置ObjectMapper的日期格式來避免生成冗長的日期字符串。這可以減小JSON字符串的大小,提高傳輸和解析的效率。
總之,高效地使用ObjectMapper可以避免不必要的性能損耗和潛在的問題。通過復(fù)用ObjectMapper實(shí)例、配置共享、確保線程安全以及采用其他優(yōu)化措施,我們可以充分發(fā)揮ObjectMapper的強(qiáng)大功能,提高Java應(yīng)用程序的性能和穩(wěn)定性。
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); } } }
到此這篇關(guān)于Java ObjectMapper的使用和使用過程中遇到的問題的文章就介紹到這了,更多相關(guān)Java ObjectMapper使用內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java使用JaCoCo進(jìn)行代碼覆蓋率分析的操作指南
JaCoCo是一個(gè)開源的 Java 代碼覆蓋率工具,廣泛應(yīng)用于測試過程中,它可以幫助開發(fā)者分析測試代碼的覆蓋情況,在本文中,我們將介紹 JaCoCo 的基本功能、如何集成到 Maven 項(xiàng)目中,以及通過具體案例展示如何生成覆蓋率報(bào)告,需要的朋友可以參考下2025-02-02SpringBoot配置MySQL5.7與MySQL8.0的異同點(diǎn)詳解
MySQL 是 Java 開發(fā)中最常用的數(shù)據(jù)庫之一,而 Spring Boot 提供了便捷的配置方式,隨著 MySQL 8.0 的普及,許多開發(fā)者需要從 MySQL 5.7 升級(jí)到 8.0,在實(shí)際開發(fā)中,二者的配置方式既有相似之處,也有一些需要特別注意的不同點(diǎn),所以本文給大家詳細(xì)介紹了它們的異同點(diǎn)2024-12-12springboot整合xxl-job的實(shí)現(xiàn)示例
本文主要介紹了springboot整合xxl-job的實(shí)現(xiàn)示例,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2023-06-06Springboot2.6.x的啟動(dòng)流程與自動(dòng)配置詳解
這篇文章主要給大家介紹了關(guān)于Springboot2.6.x的啟動(dòng)流程與自動(dòng)配置的相關(guān)資料,文中通過實(shí)例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2022-01-01