Skip to content

Commit

Permalink
add jackson annotation JsonFormat support, for issue #1003
Browse files Browse the repository at this point in the history
  • Loading branch information
wenshao committed Dec 9, 2022
1 parent 0aee560 commit 710a043
Show file tree
Hide file tree
Showing 9 changed files with 310 additions and 1 deletion.
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.alibaba.fastjson2.adapter.jackson.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target({ElementType.ANNOTATION_TYPE, ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER,
ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface JsonFormat {
String pattern() default "";
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
package com.alibaba.fastjson2.adapter.jackson.databind;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONReader;
import com.alibaba.fastjson2.JSONWriter;
import com.alibaba.fastjson2.adapter.jackson.annotation.JsonFormat;
import org.junit.jupiter.api.Test;

import java.time.LocalTime;

import static org.junit.jupiter.api.Assertions.assertEquals;

public class JsonFormatTest {
@Test
public void test() {
Bean bean = new Bean();
bean.time = LocalTime.of(12, 13, 14);
String str = JSON.toJSONString(bean);
assertEquals("{\"time\":\"121314\"}", str);
Bean bean1 = JSON.parseObject(str, Bean.class);
assertEquals(bean.time, bean1.time);
}

public static class Bean {
@JsonFormat(pattern = "HHmmss")
public LocalTime time;
}

@Test
public void test1() {
Bean1 bean = new Bean1();
bean.time = LocalTime.of(12, 13, 14);
String str = JSON.toJSONString(bean);
assertEquals("{\"time\":\"121314\"}", str);
Bean1 bean1 = JSON.parseObject(str, Bean1.class);
assertEquals(bean.time, bean1.time);
}

public static class Bean1 {
private LocalTime time;

@JsonFormat(pattern = "HHmmss")
public LocalTime getTime() {
return time;
}

@JsonFormat(pattern = "HHmmss")
public void setTime(LocalTime time) {
this.time = time;
}
}

@Test
public void test3() {
Bean3 bean = new Bean3();
bean.time = LocalTime.of(12, 13, 14);
String str = JSON.toJSONString(bean);
assertEquals("{\"time\":\"121314\"}", str);
Bean3 bean1 = JSON.parseObject(str, Bean3.class);
assertEquals(bean.time, bean1.time);
}

@Test
public void test3F() {
Bean3 bean = new Bean3();
bean.time = LocalTime.of(12, 13, 14);
String str = JSON.toJSONString(bean, JSONWriter.Feature.FieldBased);
assertEquals("{\"time\":\"121314\"}", str);
Bean3 bean1 = JSON.parseObject(str, Bean3.class, JSONReader.Feature.FieldBased);
assertEquals(bean.time, bean1.time);
}

@JsonFormat(pattern = "HHmmss")
public static class Bean3 {
public LocalTime time;
}

@Test
public void test4() {
Bean4 bean = new Bean4();
bean.time = LocalTime.of(12, 13, 14);
String str = JSON.toJSONString(bean);
assertEquals("{\"time\":\"121314\"}", str);
Bean4 bean1 = JSON.parseObject(str, Bean4.class);
assertEquals(bean.time, bean1.time);
}

@JsonFormat(pattern = "HHmmss")
public static class Bean4 {
private LocalTime time;

public LocalTime getTime() {
return time;
}

public void setTime(LocalTime time) {
this.time = time;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
import java.util.regex.Pattern;

import static com.alibaba.fastjson2.util.AnnotationUtils.getAnnotations;
import static com.alibaba.fastjson2.util.BeanUtils.processJacksonJsonFormat;
import static com.alibaba.fastjson2.util.BeanUtils.processJacksonJsonIgnore;
import static com.alibaba.fastjson2.util.JDKUtils.UNSAFE_SUPPORT;

Expand Down Expand Up @@ -255,6 +256,12 @@ public void getBeanInfo(BeanInfo beanInfo, Class<?> objectClass) {
processJacksonJsonTypeName(beanInfo, annotation);
}
break;
case "com.fasterxml.jackson.annotation.JsonFormat":
case "com.alibaba.fastjson2.adapter.jackson.annotation.JsonFormat":
if (useJacksonAnnotation) {
processJacksonJsonFormat(beanInfo, annotation);
}
break;
case "com.fasterxml.jackson.annotation.JsonSubTypes":
case "com.alibaba.fastjson2.adapter.jackson.annotation.JsonSubTypes":
if (useJacksonAnnotation) {
Expand Down Expand Up @@ -707,6 +714,12 @@ public void getFieldInfo(FieldInfo fieldInfo, Class objectClass, Method method)
processJacksonJsonDeserialize(fieldInfo, annotation);
}
break;
case "com.fasterxml.jackson.annotation.JsonFormat":
case "com.alibaba.fastjson2.adapter.jackson.annotation.JsonFormat":
if (useJacksonAnnotation) {
processJacksonJsonFormat(fieldInfo, annotation);
}
break;
case "com.fasterxml.jackson.annotation.JsonAnySetter":
case "com.alibaba.fastjson2.adapter.jackson.annotation.JsonAnySetter":
if (useJacksonAnnotation) {
Expand Down Expand Up @@ -822,6 +835,12 @@ private void processAnnotation(FieldInfo fieldInfo, Annotation[] annotations) {
processJacksonJsonProperty(fieldInfo, annotation);
}
break;
case "com.fasterxml.jackson.annotation.JsonFormat":
case "com.alibaba.fastjson2.adapter.jackson.annotation.JsonFormat":
if (useJacksonAnnotation) {
processJacksonJsonFormat(fieldInfo, annotation);
}
break;
case "com.fasterxml.jackson.databind.annotation.JsonDeserialize":
case "com.alibaba.fastjson2.adapter.jackson.databind.annotation.JsonDeserialize":
if (useJacksonAnnotation) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1297,20 +1297,24 @@ protected <T> FieldReader[] createFieldReaders(

BeanInfo finalBeanInfo = beanInfo;
final long beanFeatures = beanInfo.readerFeatures;
final String beanFormat = beanInfo.format;
final FieldInfo fieldInfo = new FieldInfo();
final String[] orders = beanInfo.orders;
if (fieldBased) {
BeanUtils.declaredFields(objectClass, field -> {
fieldInfo.init();
fieldInfo.features |= JSONReader.Feature.FieldBased.mask;
fieldInfo.features |= beanFeatures;
fieldInfo.format = beanFormat;

createFieldReader(objectClass, objectType, namingStrategy, fieldInfo, field, fieldReaders, provider);
});
} else {
BeanUtils.declaredFields(objectClass, field -> {
fieldInfo.init();
fieldInfo.ignore = (field.getModifiers() & Modifier.PUBLIC) == 0;
fieldInfo.features |= beanFeatures;
fieldInfo.format = beanFormat;

createFieldReader(objectClass, objectType, namingStrategy, fieldInfo, field, fieldReaders, provider);
if (fieldInfo.required) {
Expand All @@ -1325,6 +1329,7 @@ protected <T> FieldReader[] createFieldReaders(
BeanUtils.setters(objectClass, method -> {
fieldInfo.init();
fieldInfo.features |= beanFeatures;
fieldInfo.format = beanFormat;
createFieldReader(objectClass, objectType, namingStrategy, orders, fieldInfo, method, fieldReaders, provider);
});

Expand Down
46 changes: 46 additions & 0 deletions core/src/main/java/com/alibaba/fastjson2/util/BeanUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -2278,4 +2278,50 @@ public static void processJSONType1x(BeanInfo beanInfo, Annotation jsonType1x, M
ignored.printStackTrace();
}
}

public static void processJacksonJsonFormat(FieldInfo fieldInfo, Annotation annotation) {
Class<? extends Annotation> annotationClass = annotation.getClass();
BeanUtils.annotationMethods(annotationClass, m -> {
String name = m.getName();
try {
Object result = m.invoke(annotation);
switch (name) {
case "pattern": {
String pattern = (String) result;
if (pattern.length() != 0) {
fieldInfo.format = pattern;
}
break;
}
default:
break;
}
} catch (Throwable ignored) {
// ignored
}
});
}

public static void processJacksonJsonFormat(BeanInfo beanInfo, Annotation annotation) {
Class<? extends Annotation> annotationClass = annotation.getClass();
BeanUtils.annotationMethods(annotationClass, m -> {
String name = m.getName();
try {
Object result = m.invoke(annotation);
switch (name) {
case "pattern": {
String pattern = (String) result;
if (pattern.length() != 0) {
beanInfo.format = pattern;
}
break;
}
default:
break;
}
} catch (Throwable ignored) {
// ignored
}
});
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@

import static com.alibaba.fastjson2.codec.FieldInfo.JSON_AUTO_WIRED_ANNOTATED;
import static com.alibaba.fastjson2.util.AnnotationUtils.getAnnotations;
import static com.alibaba.fastjson2.util.BeanUtils.processJacksonJsonFormat;
import static com.alibaba.fastjson2.util.BeanUtils.processJacksonJsonIgnore;

public class ObjectWriterBaseModule
Expand Down Expand Up @@ -111,6 +112,12 @@ public void getBeanInfo(BeanInfo beanInfo, Class objectClass) {
processJacksonJsonPropertyOrder(beanInfo, annotation);
}
break;
case "com.fasterxml.jackson.annotation.JsonFormat":
case "com.alibaba.fastjson2.adapter.jackson.annotation.JsonFormat":
if (useJacksonAnnotation) {
processJacksonJsonFormat(beanInfo, annotation);
}
break;
case "com.fasterxml.jackson.annotation.JsonTypeInfo":
case "com.alibaba.fastjson2.adapter.jackson.annotation.JsonTypeInfo":
if (useJacksonAnnotation) {
Expand Down Expand Up @@ -343,6 +350,12 @@ public void getFieldInfo(BeanInfo beanInfo, FieldInfo fieldInfo, Class objectTyp
processJacksonJsonProperty(fieldInfo, annotation);
}
break;
case "com.fasterxml.jackson.annotation.JsonFormat":
case "com.alibaba.fastjson2.adapter.jackson.annotation.JsonFormat":
if (useJacksonAnnotation) {
processJacksonJsonFormat(fieldInfo, annotation);
}
break;
case "com.alibaba.fastjson2.adapter.jackson.databind.annotation.JsonSerialize":
case "com.fasterxml.jackson.databind.annotation.JsonSerialize":
if (useJacksonAnnotation) {
Expand Down Expand Up @@ -870,6 +883,12 @@ private void processAnnotations(FieldInfo fieldInfo, Annotation[] annotations) {
}
break;
}
case "com.fasterxml.jackson.annotation.JsonFormat":
case "com.alibaba.fastjson2.adapter.jackson.annotation.JsonFormat":
if (useJacksonAnnotation) {
processJacksonJsonFormat(fieldInfo, annotation);
}
break;
case "com.fasterxml.jackson.annotation.JsonValue":
case "com.alibaba.fastjson2.adapter.jackson.annotation.JsonValue":
if (useJacksonAnnotation) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -218,7 +218,12 @@ protected FieldWriter creteFieldWriter(
}
}

return createFieldWriter(provider, fieldName, fieldInfo.ordinal, fieldInfo.features, fieldInfo.format, fieldInfo.label, field, writeUsingWriter);
String format = fieldInfo.format;
if (format == null && beanInfo.format != null) {
format = beanInfo.format;
}

return createFieldWriter(provider, fieldName, fieldInfo.ordinal, fieldInfo.features, format, fieldInfo.label, field, writeUsingWriter);
}

protected ObjectWriter getAnnotatedObjectWriter(ObjectWriterProvider provider,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,8 @@ boolean record = BeanUtils.isRecord(objectClass);
BeanUtils.getters(objectClass, method -> {
fieldInfo.init();
fieldInfo.features |= writerFieldFeatures;
fieldInfo.format = beanInfo.format;

provider.getFieldInfo(beanInfo, fieldInfo, objectClass, method);
if (fieldInfo.ignore) {
return;
Expand Down

0 comments on commit 710a043

Please sign in to comment.