Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 17 additions & 27 deletions pom.xml
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.5.7</version>
<version>4.0.0</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>

Expand Down Expand Up @@ -52,7 +53,7 @@
<dependency>
<groupId>io.github.classgraph</groupId>
<artifactId>classgraph</artifactId>
<version>4.8.181</version>
<version>4.8.184</version>
</dependency>


Expand All @@ -61,7 +62,7 @@
<dependency>
<groupId>commons-validator</groupId>
<artifactId>commons-validator</artifactId>
<version>1.10.0</version>
<version>1.10.1</version>
<exclusions>
<exclusion>
<groupId>commons-collections</groupId>
Expand All @@ -78,7 +79,7 @@
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
<version>2.8.14</version>
<version>3.0.0</version>
</dependency>

<!-- Testing -->
Expand All @@ -98,13 +99,18 @@
<artifactId>spring-boot-starter-web</artifactId>
<scope>test</scope>
</dependency>

<!-- Database -->
<dependency>
<groupId>org.liquibase</groupId>
<artifactId>liquibase-core</artifactId>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-webmvc-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-liquibase</artifactId>
<scope>test</scope>
</dependency>

<!-- Database -->
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
Expand All @@ -117,22 +123,6 @@
<artifactId>testcontainers</artifactId>
<version>2.0.2</version>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.hamcrest</groupId>
<artifactId>hamcrest-core</artifactId>
</exclusion>
<exclusion>
<groupId>org.hamcrest</groupId>
<artifactId>hamcrest-library</artifactId>
</exclusion>
<exclusion>
<!-- see: https://github.com/testcontainers/testcontainers-java/issues/970#issuecomment-625044008 -->
<!-- can be removed once testcontainers drop their dependency to junit4 -->
<groupId>junit</groupId>
<artifactId>junit</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.testcontainers</groupId>
Expand Down Expand Up @@ -195,12 +185,12 @@
<dependency>
<groupId>com.puppycrawl.tools</groupId>
<artifactId>checkstyle</artifactId>
<version>11.1.0</version>
<version>12.3.0</version>
</dependency>
<dependency>
<groupId>it.aboutbits</groupId>
<artifactId>java-checkstyle-config</artifactId>
<version>1.0.1</version>
<version>1.1.0</version>
</dependency>
</dependencies>
</plugin>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,13 @@
import it.aboutbits.springboot.toolbox.type.identity.EntityId;
import it.aboutbits.springboot.toolbox.web.CustomTypePropertyEditor;
import it.aboutbits.springboot.toolbox.web.EntityIdPropertyEditor;
import org.springframework.boot.autoconfigure.jackson.Jackson2ObjectMapperBuilderCustomizer;
import org.springframework.boot.jackson.autoconfigure.JsonMapperBuilderCustomizer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.InitBinder;
import tools.jackson.databind.module.SimpleModule;

import java.util.Set;

Expand All @@ -37,19 +38,23 @@ public void initBinder(WebDataBinder binder) {
}

@Bean
public Jackson2ObjectMapperBuilderCustomizer jsonCustomizer(CustomTypeScanner configuration) {
var types = configuration.getRelevantTypes();
public JsonMapperBuilderCustomizer jsonCustomizer(CustomTypeScanner configuration) {
var module = new SimpleModule();

var deserializers = types.stream()
.map(CustomTypeDeserializer::new)
.toList()
.toArray(new CustomTypeDeserializer[types.size()]);
// serializers
module.addSerializer(new CustomTypeSerializer());

// dynamic deserializers
configuration.getRelevantTypes()
.forEach(type ->
module.addDeserializer(type, new CustomTypeDeserializer(type))
);
Comment on lines +49 to +51

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please auto-format all files.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It reformatted a few things, but not that one 🤷


// type-based deserializer
module.addDeserializer(EntityId.class, new EntityIdDeserializer());

return builder -> builder
.serializers(new CustomTypeSerializer())
.deserializers(deserializers)
.deserializerByType(EntityId.class, new EntityIdDeserializer());
.addModule(module);
}

}
Original file line number Diff line number Diff line change
@@ -1,21 +1,24 @@
package it.aboutbits.springboot.toolbox.jackson;

import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import it.aboutbits.springboot.toolbox.reflection.util.CustomTypeReflectionUtil;
import it.aboutbits.springboot.toolbox.type.CustomType;
import it.aboutbits.springboot.toolbox.type.ScaledBigDecimal;
import tools.jackson.core.JacksonException;
import tools.jackson.core.JsonParser;
import tools.jackson.core.TokenStreamLocation;
import tools.jackson.core.exc.InputCoercionException;
import tools.jackson.databind.DeserializationContext;
import tools.jackson.databind.ValueDeserializer;

import java.io.IOException;
import java.io.Closeable;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.UUID;
import java.util.function.Function;

public class CustomTypeDeserializer<T extends CustomType<?>> extends JsonDeserializer<T> {
public class CustomTypeDeserializer<T extends CustomType<?>> extends ValueDeserializer<T> {
private final Class<T> customType;
private final Constructor<T> constructor;
private final Function<JsonParser, Object> typeConverter;
Expand Down Expand Up @@ -43,7 +46,7 @@ public Class<T> handledType() {
}

@Override
public T deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException {
public T deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) {
var value = typeConverter.apply(jsonParser);

try {
Expand All @@ -52,7 +55,46 @@ public T deserialize(JsonParser jsonParser, DeserializationContext deserializati
IllegalAccessException
| InvocationTargetException
| InstantiationException e) {
throw new IOException(e);
throw new Ex(e);
}
}

public static class Ex extends JacksonException {

protected Ex(String msg) {
super(msg);
}

protected Ex(Throwable rootCause) {
super(rootCause);
}

protected Ex(String msg, Throwable rootCause) {
super(msg, rootCause);
}

protected Ex(String msg, TokenStreamLocation loc, Throwable rootCause) {
super(msg, loc, rootCause);
}

protected Ex(Closeable processor, Throwable rootCause) {
super(processor, rootCause);
}

protected Ex(Closeable processor, String msg, TokenStreamLocation loc, Throwable rootCause) {
super(processor, msg, loc, rootCause);
}

protected Ex(Closeable processor, String msg) {
super(processor, msg);
}

protected Ex(Closeable processor, String msg, Throwable problem) {
super(processor, msg, problem);
}

protected Ex(Closeable processor, String msg, TokenStreamLocation loc) {
super(processor, msg, loc);
}
}

Expand Down Expand Up @@ -106,7 +148,7 @@ private static Function<JsonParser, Object> getByteConverter() {
return jsonParser -> {
try {
return jsonParser.getByteValue();
} catch (IOException e) {
} catch (InputCoercionException e) {
throw new CustomTypeDeserializerException("Failed to read value as Byte.", e);
}
};
Expand All @@ -116,7 +158,7 @@ private static Function<JsonParser, Object> getBooleanConverter() {
return jsonParser -> {
try {
return jsonParser.getBooleanValue();
} catch (IOException e) {
} catch (InputCoercionException e) {
throw new CustomTypeDeserializerException("Failed to read value as Boolean.", e);
}
};
Expand All @@ -126,7 +168,7 @@ private static Function<JsonParser, Object> getScaledBigDecimalConverter() {
return jsonParser -> {
try {
return new ScaledBigDecimal(jsonParser.getDecimalValue());
} catch (IOException e) {
} catch (InputCoercionException e) {
throw new CustomTypeDeserializerException("Failed to read value as ScaledBigDecimal.", e);
}
};
Expand All @@ -136,7 +178,7 @@ private static Function<JsonParser, Object> getBigDecimalConverter() {
return jsonParser -> {
try {
return jsonParser.getDecimalValue();
} catch (IOException e) {
} catch (InputCoercionException e) {
throw new CustomTypeDeserializerException("Failed to read value as BigDecimal.", e);
}
};
Expand All @@ -146,7 +188,7 @@ private static Function<JsonParser, Object> getDoubleConverter() {
return jsonParser -> {
try {
return jsonParser.getDoubleValue();
} catch (IOException e) {
} catch (InputCoercionException e) {
throw new CustomTypeDeserializerException("Failed to read value as Double.", e);
}
};
Expand All @@ -156,7 +198,7 @@ private static Function<JsonParser, Object> getFloatConverter() {
return jsonParser -> {
try {
return jsonParser.getFloatValue();
} catch (IOException e) {
} catch (InputCoercionException e) {
throw new CustomTypeDeserializerException("Failed to read value as Float.", e);
}
};
Expand All @@ -166,7 +208,7 @@ private static Function<JsonParser, Object> getBigIntegerConverter() {
return jsonParser -> {
try {
return jsonParser.getBigIntegerValue();
} catch (IOException e) {
} catch (InputCoercionException e) {
throw new CustomTypeDeserializerException("Failed to read value as BigInteger.", e);
}
};
Expand All @@ -176,7 +218,7 @@ private static Function<JsonParser, Object> getLongConverter() {
return jsonParser -> {
try {
return jsonParser.getLongValue();
} catch (IOException e) {
} catch (InputCoercionException e) {
throw new CustomTypeDeserializerException("Failed to read value as Long.", e);
}
};
Expand All @@ -186,7 +228,7 @@ private static Function<JsonParser, Object> getIntegerConverter() {
return jsonParser -> {
try {
return jsonParser.getIntValue();
} catch (IOException e) {
} catch (InputCoercionException e) {
throw new CustomTypeDeserializerException("Failed to read value as Integer.", e);
}
};
Expand All @@ -196,7 +238,7 @@ private static Function<JsonParser, Object> getShortConverter() {
return jsonParser -> {
try {
return jsonParser.getShortValue();
} catch (IOException e) {
} catch (InputCoercionException e) {
throw new CustomTypeDeserializerException("Failed to read value as Short.", e);
}
};
Expand All @@ -206,7 +248,7 @@ private static Function<JsonParser, Object> getStringConverter() {
return jsonParser -> {
try {
return jsonParser.getValueAsString();
} catch (IOException e) {
} catch (InputCoercionException e) {
throw new CustomTypeDeserializerException("Failed to read value as String.", e);
}
};
Expand All @@ -217,10 +259,15 @@ private static Function<JsonParser, Object> getCharConverter() {
try {
var value = jsonParser.getValueAsString();
if (value == null || value.length() != 1) {
throw new IOException();
throw new InputCoercionException(
jsonParser,
"Not a Char.",
jsonParser.currentToken(),
String.class
);
}
return value.charAt(0);
} catch (IOException e) {
} catch (InputCoercionException e) {
throw new CustomTypeDeserializerException("Failed to read value as Char.", e);
}
};
Expand All @@ -231,10 +278,15 @@ private static Function<JsonParser, Object> getUUIDConverter() {
try {
var value = jsonParser.getValueAsString();
if (value == null || value.length() != 36) {
throw new IOException();
throw new InputCoercionException(
jsonParser,
"Not a UUID.",
jsonParser.currentToken(),
String.class
);
}
return UUID.fromString(value);
} catch (IOException e) {
} catch (InputCoercionException e) {
throw new CustomTypeDeserializerException("Failed to read value as UUID.", e);
}
};
Expand All @@ -255,7 +307,7 @@ private static Function<JsonParser, Object> getEnumConverter(Class<?> wrappedTyp
"Failed to read value as Enum: " + enumClass.getName(),
e
);
} catch (IOException e) {
} catch (InputCoercionException e) {
throw new CustomTypeDeserializerException("Failed to read value as Enum.", e);
}
};
Expand Down
Loading