Skip to content

Commit

Permalink
json
Browse files Browse the repository at this point in the history
  • Loading branch information
ponfee committed Jan 27, 2024
1 parent 8b69c17 commit 811abe8
Show file tree
Hide file tree
Showing 3 changed files with 77 additions and 98 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -16,20 +16,12 @@
import cn.ponfee.disjob.id.snowflake.db.DbDistributedSnowflake;
import cn.ponfee.disjob.supervisor.configuration.EnableSupervisor;
import cn.ponfee.disjob.worker.configuration.EnableWorker;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.lang.Nullable;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

import java.math.BigInteger;

import static cn.ponfee.disjob.supervisor.dao.SupervisorDataSourceConfig.JDBC_TEMPLATE_SPRING_BEAN_NAME;

Expand All @@ -41,30 +33,17 @@
@Configuration
@ComponentScan("cn.ponfee.disjob.test.handler")
@EnableJacksonDateConfigurer // 解决日期反序列化报错的问题
@EnableSupervisor // disjob-admin必须启用Supervisor角色,即:必须加@EnableSupervisor注解
@EnableWorker // 若要取消worker角色可去掉@EnableWorker注解
public class DisjobAdminConfiguration implements WebMvcConfigurer {

public DisjobAdminConfiguration(@Nullable ObjectMapper objectMapper) {
if (objectMapper == null) {
throw new Error("Not found jackson object mapper in spring container.");
}
objectMapper.enable(JsonGenerator.Feature.WRITE_BIGDECIMAL_AS_PLAIN);

SimpleModule simpleModule = new SimpleModule();
// 返回给端上浏览器JavaScript Number数值过大时会有问题:Number.MAX_SAFE_INTEGER = 9007199254740991
// 当数值大于`9007199254740991`时就有可能会丢失精度:1234567891011121314 -> 1234567891011121400
simpleModule.addSerializer(Long.class, ToStringSerializer.instance);
simpleModule.addSerializer(long.class, ToStringSerializer.instance);
simpleModule.addSerializer(BigInteger.class, ToStringSerializer.instance);
objectMapper.registerModule(simpleModule);
}
@EnableSupervisor // disjob-admin必须启用Supervisor角色,即:必须加@EnableSupervisor注解
@EnableWorker // 若要取消worker角色可去掉@EnableWorker注解
public class DisjobAdminConfiguration {

@Bean
public IdGenerator idGenerator(@Qualifier(JDBC_TEMPLATE_SPRING_BEAN_NAME) JdbcTemplate jdbcTemplate,
@Value("${" + JobConstants.SPRING_WEB_SERVER_PORT + "}") int port,
@Value("${" + JobConstants.DISJOB_BOUND_SERVER_HOST + ":}") String boundHost) {
return new DbDistributedSnowflake(jdbcTemplate, JobConstants.DISJOB_KEY_PREFIX, JobUtils.getLocalHost(boundHost) + Char.COLON + port);
// serverTag = host:port
String serverTag = JobUtils.getLocalHost(boundHost) + Char.COLON + port;
return new DbDistributedSnowflake(jdbcTemplate, JobConstants.DISJOB_KEY_PREFIX, serverTag);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -8,24 +8,15 @@

package cn.ponfee.disjob.common.spring;

import cn.ponfee.disjob.common.date.*;
import cn.ponfee.disjob.common.date.JavaUtilDateFormat;
import cn.ponfee.disjob.common.util.Jsons;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateDeserializer;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalTimeSerializer;
import com.fasterxml.jackson.datatype.jdk8.Jdk8Module;
import org.springframework.context.annotation.Import;
import org.springframework.lang.Nullable;

import java.lang.annotation.*;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.util.Date;

/**
* Enable object mapper configurer
Expand All @@ -45,25 +36,11 @@ public ObjectMapperConfigurer(@Nullable ObjectMapper objectMapper) {
return;
}

objectMapper.enable(JsonGenerator.Feature.WRITE_BIGDECIMAL_AS_PLAIN);
objectMapper.setDateFormat(JavaUtilDateFormat.DEFAULT);

SimpleModule module = new SimpleModule();
module.addSerializer(Date.class, JacksonDate.INSTANCE.serializer());
module.addDeserializer(Date.class, JacksonDate.INSTANCE.deserializer());
objectMapper.registerModule(module);

// java.time.LocalDateTime
DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern(Dates.DATE_PATTERN);
DateTimeFormatter timeFormatter = DateTimeFormatter.ofPattern("HH:mm:ss");

JavaTimeModule javaTimeModule = new JavaTimeModule();
javaTimeModule.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(LocalDateTimeFormat.PATTERN_11));
javaTimeModule.addDeserializer(LocalDateTime.class, CustomLocalDateTimeDeserializer.INSTANCE);
javaTimeModule.addSerializer(LocalDate.class, new LocalDateSerializer(dateFormatter));
javaTimeModule.addDeserializer(LocalDate.class, new LocalDateDeserializer(dateFormatter));
javaTimeModule.addSerializer(LocalTime.class, new LocalTimeSerializer(timeFormatter));
javaTimeModule.addDeserializer(LocalTime.class, new LocalTimeDeserializer(timeFormatter));
objectMapper.registerModule(javaTimeModule);
Jsons.registerSimpleModule(objectMapper);
Jsons.registerJavaTimeModule(objectMapper);
objectMapper.registerModule(new Jdk8Module());
}
}

Expand Down
103 changes: 63 additions & 40 deletions disjob-common/src/main/java/cn/ponfee/disjob/common/util/Jsons.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.datatype.jdk8.Jdk8Module;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateDeserializer;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalTimeDeserializer;
Expand Down Expand Up @@ -191,6 +192,7 @@ public <T> T parse(byte[] json, TypeReference<T> type) {
}

// ----------------------------------------------------static methods

public static String toJson(Object target) {
return NORMAL.string(target);
}
Expand All @@ -204,18 +206,18 @@ public static Object[] parseArray(String body, Class<?>... types) {
return null;
}

ObjectMapper mapper = NORMAL.mapper;
JsonNode rootNode = readTree(mapper, body);
ObjectMapper objectMapper = NORMAL.mapper;
JsonNode rootNode = readTree(objectMapper, body);
Assert.isTrue(rootNode.isArray(), "Not array json data.");
ArrayNode arrayNode = (ArrayNode) rootNode;

if (types.length == 1 && arrayNode.size() > 1) {
return new Object[]{parse(mapper, arrayNode, types[0])};
return new Object[]{parse(objectMapper, arrayNode, types[0])};
}

Object[] result = new Object[types.length];
for (int i = 0; i < types.length; i++) {
result[i] = parse(mapper, arrayNode.get(i), types[i]);
result[i] = parse(objectMapper, arrayNode.get(i), types[i]);
}
return result;
}
Expand All @@ -234,16 +236,16 @@ public static Object[] parseMethodArgs(String body, Method method) {
return null;
}

ObjectMapper mapper = NORMAL.mapper;
JsonNode rootNode = readTree(mapper, body);
ObjectMapper objectMapper = NORMAL.mapper;
JsonNode rootNode = readTree(objectMapper, body);
if (rootNode.isArray()) {
ArrayNode arrayNode = (ArrayNode) rootNode;

// 方法只有一个参数,但请求参数长度大于1
// ["a", "b"] -> method(Object[] arg) -> arg=["a", "b"]
// [["a"], ["b"]] -> method(Object[] arg) -> arg=[["a"], ["b"]]
if (argumentCount == 1 && arrayNode.size() > 1) {
return new Object[]{parse(mapper, arrayNode, genericArgumentTypes[0])};
return new Object[]{parse(objectMapper, arrayNode, genericArgumentTypes[0])};
}

// 其它情况,在调用方将参数(requestParameters)用数组包一层:new Object[]{ arg-1, arg-2, ..., arg-n }
Expand All @@ -257,12 +259,12 @@ public static Object[] parseMethodArgs(String body, Method method) {

Object[] methodArguments = new Object[argumentCount];
for (int i = 0; i < argumentCount; i++) {
methodArguments[i] = parse(mapper, arrayNode.get(i), genericArgumentTypes[i]);
methodArguments[i] = parse(objectMapper, arrayNode.get(i), genericArgumentTypes[i]);
}
return methodArguments;
} else {
Assert.isTrue(argumentCount == 1, "Single object request parameter not support multiple arguments method.");
return new Object[]{parse(mapper, rootNode, genericArgumentTypes[0])};
return new Object[]{parse(objectMapper, rootNode, genericArgumentTypes[0])};
}
}

Expand Down Expand Up @@ -318,44 +320,66 @@ public static ObjectMapper createObjectMapper(JsonInclude.Include include) {
JsonFactory jsonFactory = new JsonFactoryBuilder()
.disable(JsonFactory.Feature.INTERN_FIELD_NAMES)
.build();
ObjectMapper mapper = new ObjectMapper(jsonFactory);
ObjectMapper objectMapper = new ObjectMapper(jsonFactory);
// 设置序列化时的特性
if (include != null) {
mapper.setSerializationInclusion(include);
objectMapper.setSerializationInclusion(include);
}
configObjectMapper(mapper);
return mapper;
configObjectMapper(objectMapper);
return objectMapper;
}

public static void configObjectMapper(ObjectMapper mapper) {
// 1、Common config
mapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES); // 反序列化时忽略未知属性
mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS); // Date不序列化为时间戳
mapper.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS); // 解决报错:No serializer found for class XXX and no properties discovered to create BeanSerializer
mapper.enable(JsonGenerator.Feature.WRITE_BIGDECIMAL_AS_PLAIN); // BigDecimal禁用科学计数格式输出,new BigDecimal("0.00000000000000001"): 1E-17 -> 0.00000000000000001
mapper.disable(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES); // 禁止无双引号字段
mapper.enable(JsonWriteFeature.QUOTE_FIELD_NAMES.mappedFeature()); // 字段加双引号
public static void configObjectMapper(ObjectMapper objectMapper) {
// Common config
objectMapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES); // 反序列化时忽略未知属性
objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS); // Date不序列化为时间戳
objectMapper.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS); // 解决报错:No serializer found for class XXX and no properties discovered to create BeanSerializer
objectMapper.enable(JsonGenerator.Feature.WRITE_BIGDECIMAL_AS_PLAIN); // BigDecimal禁用科学计数格式输出,new BigDecimal("0.00000000000000001"): 1E-17 -> 0.00000000000000001
objectMapper.disable(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES); // 禁止无双引号字段
objectMapper.enable(JsonWriteFeature.QUOTE_FIELD_NAMES.mappedFeature()); // 字段加双引号

// 2、java.util.Date config
// java.util.Date config
// java.util.Date:registerModule > JsonFormat(会使用setTimeZone) > setDateFormat(会使用setTimeZone)
// 1)如果同时配置了setDateFormat和registerModule,则使用registerModule
// 2)如果设置了setTimeZone,则会调用setDateFormat#setTimeZone(注:setTimeZone对registerModule无影响)
// 3)如果实体字段使用了JsonFormat注解,则setDateFormat不生效(会使用jackson内置的格式化器,默认为0时区,此时要setTimeZone)
// 4)JsonFormat注解对registerModule无影响(registerModule优先级最高)
mapper.setTimeZone(JavaUtilDateFormat.DEFAULT.getTimeZone()); // TimeZone.getDefault()
mapper.setDateFormat(JavaUtilDateFormat.DEFAULT);
//mapper.setConfig(mapper.getDeserializationConfig().with(mapper.getDateFormat()));
//mapper.setConfig(mapper.getSerializationConfig().with(mapper.getDateFormat()));

// 3、java.util.Date module config
SimpleModule module = new SimpleModule();
module.addSerializer(Date.class, JacksonDate.INSTANCE.serializer());
module.addDeserializer(Date.class, JacksonDate.INSTANCE.deserializer());
//module.addSerializer(Money.class, JacksonMoney.INSTANCE.serializer());
//module.addDeserializer(Money.class, JacksonMoney.INSTANCE.deserializer());
mapper.registerModule(module);

// 4、java.time.LocalDateTime module config
objectMapper.setTimeZone(JavaUtilDateFormat.DEFAULT.getTimeZone()); // TimeZone.getDefault()
objectMapper.setDateFormat(JavaUtilDateFormat.DEFAULT);
//objectMapper.setConfig(mapper.getDeserializationConfig().with(mapper.getDateFormat()));
//objectMapper.setConfig(mapper.getSerializationConfig().with(mapper.getDateFormat()));

// register module
registerSimpleModule(objectMapper);
registerJavaTimeModule(objectMapper);
objectMapper.registerModule(new Jdk8Module());

// Others config
//objectMapper.setPropertyNamingStrategy(PropertyNamingStrategies.SNAKE_CASE);
}

public static void registerSimpleModule(ObjectMapper objectMapper) {
SimpleModule simpleModule = new SimpleModule();

// java.util.Date module config
simpleModule.addSerializer(Date.class, JacksonDate.INSTANCE.serializer());
simpleModule.addDeserializer(Date.class, JacksonDate.INSTANCE.deserializer());

// 金额序列化
//simpleModule.addSerializer(Money.class, JacksonMoney.INSTANCE.serializer());
//simpleModule.addDeserializer(Money.class, JacksonMoney.INSTANCE.deserializer());

// 返回给端上浏览器JavaScript Number数值过大时会有问题:Number.MAX_SAFE_INTEGER = 9007199254740991
// 当数值大于`9007199254740991`时就有可能会丢失精度:1234567891011121314 -> 1234567891011121400
//simpleModule.addSerializer(Long.class, ToStringSerializer.instance);
//simpleModule.addSerializer(long.class, ToStringSerializer.instance);
//simpleModule.addSerializer(BigInteger.class, ToStringSerializer.instance);

objectMapper.registerModule(simpleModule);
}

public static void registerJavaTimeModule(ObjectMapper objectMapper) {
// java new time module config
DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern(Dates.DATE_PATTERN);
DateTimeFormatter timeFormatter = DateTimeFormatter.ofPattern("HH:mm:ss");
JavaTimeModule javaTimeModule = new JavaTimeModule();
Expand All @@ -365,12 +389,11 @@ public static void configObjectMapper(ObjectMapper mapper) {
javaTimeModule.addDeserializer(LocalDate.class, new LocalDateDeserializer(dateFormatter));
javaTimeModule.addSerializer(LocalTime.class, new LocalTimeSerializer(timeFormatter));
javaTimeModule.addDeserializer(LocalTime.class, new LocalTimeDeserializer(timeFormatter));
mapper.registerModule(javaTimeModule);

// 5、Others config
//mapper.setPropertyNamingStrategy(PropertyNamingStrategies.SNAKE_CASE);
objectMapper.registerModule(javaTimeModule);
}

// -----------------------------------------------------------------------private methods

private static JsonNode readTree(ObjectMapper mapper, String body) {
try {
return mapper.readTree(body);
Expand Down

0 comments on commit 811abe8

Please sign in to comment.