From 0022153f3dc176d3fbedc4bfacba7016b18a1316 Mon Sep 17 00:00:00 2001 From: pipinet Date: Mon, 9 Oct 2023 16:38:52 +0800 Subject: [PATCH] feat: add jackson string process module --- .../jackson/datatype/PackageVersion.java | 14 ++++ .../datatype/StringProcessDeserializer.java | 52 ++++++++++++++ .../datatype/StringProcessDeserializers.java | 25 +++++++ .../jackson/datatype/StringProcessModule.java | 21 ++++++ .../com/qwlabs/jackson/datatype/Trimmed.java | 4 ++ .../jackson/datatype/StringModuleTest.java | 70 +++++++++++++++++++ 6 files changed, 186 insertions(+) create mode 100644 jackson/src/main/java/com/qwlabs/jackson/datatype/PackageVersion.java create mode 100644 jackson/src/main/java/com/qwlabs/jackson/datatype/StringProcessDeserializer.java create mode 100644 jackson/src/main/java/com/qwlabs/jackson/datatype/StringProcessDeserializers.java create mode 100644 jackson/src/main/java/com/qwlabs/jackson/datatype/StringProcessModule.java create mode 100644 jackson/src/main/java/com/qwlabs/jackson/datatype/Trimmed.java create mode 100644 jackson/src/test/java/com/qwlabs/jackson/datatype/StringModuleTest.java diff --git a/jackson/src/main/java/com/qwlabs/jackson/datatype/PackageVersion.java b/jackson/src/main/java/com/qwlabs/jackson/datatype/PackageVersion.java new file mode 100644 index 0000000..e8a5f95 --- /dev/null +++ b/jackson/src/main/java/com/qwlabs/jackson/datatype/PackageVersion.java @@ -0,0 +1,14 @@ +package com.qwlabs.jackson.datatype; + +import com.fasterxml.jackson.core.Version; +import com.fasterxml.jackson.core.Versioned; +import com.fasterxml.jackson.core.util.VersionUtil; + +public class PackageVersion implements Versioned { + public static final Version VERSION = VersionUtil.parseVersion( + "0.2.0", "com.qwlabs.doraemom", "jackson"); + @Override + public Version version() { + return VERSION; + } +} diff --git a/jackson/src/main/java/com/qwlabs/jackson/datatype/StringProcessDeserializer.java b/jackson/src/main/java/com/qwlabs/jackson/datatype/StringProcessDeserializer.java new file mode 100644 index 0000000..2afb2cd --- /dev/null +++ b/jackson/src/main/java/com/qwlabs/jackson/datatype/StringProcessDeserializer.java @@ -0,0 +1,52 @@ +package com.qwlabs.jackson.datatype; + +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.core.JsonToken; +import com.fasterxml.jackson.databind.DeserializationContext; +import com.fasterxml.jackson.databind.JsonMappingException; +import com.fasterxml.jackson.databind.annotation.JacksonStdImpl; +import com.fasterxml.jackson.databind.deser.std.StdScalarDeserializer; +import com.fasterxml.jackson.databind.jsontype.TypeDeserializer; +import com.fasterxml.jackson.databind.type.LogicalType; + +import java.io.IOException; + + +@JacksonStdImpl +public class StringProcessDeserializer extends StdScalarDeserializer { + public static final StringProcessDeserializer INSTANCE = new StringProcessDeserializer(); + + protected StringProcessDeserializer() { + super(String.class); + } + + public LogicalType logicalType() { + return LogicalType.Textual; + } + + public boolean isCachable() { + return true; + } + + public Object getEmptyValue(DeserializationContext ctxt) throws JsonMappingException { + return ""; + } + + public String deserialize(JsonParser p, DeserializationContext ctxt) throws IOException { + if (p.hasToken(JsonToken.VALUE_STRING)) { + return trim(p.getText()); + } + if (p.hasToken(JsonToken.START_ARRAY)) { + return this._deserializeFromArray(p, ctxt); + } + return trim(this._parseString(p, ctxt, this)); + } + + private String trim(String value) { + return value == null ? null : value.trim(); + } + + public String deserializeWithType(JsonParser p, DeserializationContext ctxt, TypeDeserializer typeDeserializer) throws IOException { + return this.deserialize(p, ctxt); + } +} diff --git a/jackson/src/main/java/com/qwlabs/jackson/datatype/StringProcessDeserializers.java b/jackson/src/main/java/com/qwlabs/jackson/datatype/StringProcessDeserializers.java new file mode 100644 index 0000000..a3c9ade --- /dev/null +++ b/jackson/src/main/java/com/qwlabs/jackson/datatype/StringProcessDeserializers.java @@ -0,0 +1,25 @@ +package com.qwlabs.jackson.datatype; + +import com.fasterxml.jackson.databind.BeanDescription; +import com.fasterxml.jackson.databind.DeserializationConfig; +import com.fasterxml.jackson.databind.JavaType; +import com.fasterxml.jackson.databind.JsonDeserializer; +import com.fasterxml.jackson.databind.JsonMappingException; +import com.fasterxml.jackson.databind.deser.Deserializers; + +import java.io.Serializable; + + +public class StringProcessDeserializers extends Deserializers.Base implements Serializable { + public static final StringProcessDeserializers INSTANCE = new StringProcessDeserializers(); + + @Override + public JsonDeserializer findBeanDeserializer(JavaType type, + DeserializationConfig config, + BeanDescription beanDesc) throws JsonMappingException { + if (type.hasRawClass(String.class)) { + return StringProcessDeserializer.INSTANCE; + } + return super.findBeanDeserializer(type, config, beanDesc); + } +} diff --git a/jackson/src/main/java/com/qwlabs/jackson/datatype/StringProcessModule.java b/jackson/src/main/java/com/qwlabs/jackson/datatype/StringProcessModule.java new file mode 100644 index 0000000..ded18be --- /dev/null +++ b/jackson/src/main/java/com/qwlabs/jackson/datatype/StringProcessModule.java @@ -0,0 +1,21 @@ +package com.qwlabs.jackson.datatype; + +import com.fasterxml.jackson.core.Version; +import com.fasterxml.jackson.databind.module.SimpleModule; + +public class StringProcessModule extends SimpleModule { + @Override + public String getModuleName() { + return "StringProcessModule"; + } + + @Override + public Version version() { + return PackageVersion.VERSION; + } + + @Override + public void setupModule(SetupContext setupContext) { + setupContext.addDeserializers(new StringProcessDeserializers()); + } +} diff --git a/jackson/src/main/java/com/qwlabs/jackson/datatype/Trimmed.java b/jackson/src/main/java/com/qwlabs/jackson/datatype/Trimmed.java new file mode 100644 index 0000000..1316a4c --- /dev/null +++ b/jackson/src/main/java/com/qwlabs/jackson/datatype/Trimmed.java @@ -0,0 +1,4 @@ +package com.qwlabs.jackson.datatype; + +public @interface Trimmed { +} diff --git a/jackson/src/test/java/com/qwlabs/jackson/datatype/StringModuleTest.java b/jackson/src/test/java/com/qwlabs/jackson/datatype/StringModuleTest.java new file mode 100644 index 0000000..163ea70 --- /dev/null +++ b/jackson/src/test/java/com/qwlabs/jackson/datatype/StringModuleTest.java @@ -0,0 +1,70 @@ +package com.qwlabs.jackson.datatype; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import lombok.Getter; +import lombok.Setter; +import org.junit.jupiter.api.Test; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.is; + + +class StringModuleTest { + private String leftEmpty = """ + { + "name": " d", + "value": 3 + } + """; + + private String rightEmpty = """ + { + "name": "d ", + "value": 3 + } + """; + + private String allEmpty = """ + { + "name": " d ", + "value": 3 + } + """; + + @Test + void should_trim() throws JsonProcessingException { + var objectMapper = withModule(); + + assertThat(objectMapper.readValue(leftEmpty, TestClass.class).name, is("d")); + assertThat(objectMapper.readValue(rightEmpty, TestClass.class).name, is("d")); + assertThat(objectMapper.readValue(allEmpty, TestClass.class).name, is("d")); + } + + @Test + void should_not_trim() throws JsonProcessingException { + var objectMapper = withoutModule(); + + assertThat(objectMapper.readValue(leftEmpty, TestClass.class).name, is(" d")); + assertThat(objectMapper.readValue(rightEmpty, TestClass.class).name, is("d ")); + assertThat(objectMapper.readValue(allEmpty, TestClass.class).name, is(" d ")); + } + + private ObjectMapper withoutModule() { + return new ObjectMapper(); + } + + private ObjectMapper withModule() { + var objectMapper = new ObjectMapper(); + objectMapper.registerModule(new StringProcessModule()); + return objectMapper; + } + + @Getter + @Setter + public static class TestClass { + @Trimmed + private String name; + private Integer value; + } +}