Skip to content

Commit 990b68e

Browse files
committed
feat: add Jackson 2.x datatype module and Spring Boot 3 sample
- Add friendly-id-jackson2-datatype module for Jackson 2.x compatibility - Add friendly-id-spring-boot3-simple sample demonstrating usage with Spring Boot 3.4.1 and Jackson 2.x - Update jackson-datatype module service file for Jackson 3.x
1 parent 7fc38d3 commit 990b68e

23 files changed

Lines changed: 659 additions & 0 deletions

File tree

friendly-id-jackson-datatype/src/main/resources/META-INF/services/com.fasterxml.jackson.databind.Module renamed to friendly-id-jackson-datatype/src/main/resources/META-INF/services/tools.jackson.databind.JacksonModule

File renamed without changes.
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<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">
3+
<modelVersion>4.0.0</modelVersion>
4+
5+
<parent>
6+
<artifactId>friendly-id-project</artifactId>
7+
<groupId>com.devskiller.friendly-id</groupId>
8+
<version>${revision}</version>
9+
<relativePath>..</relativePath>
10+
</parent>
11+
12+
<artifactId>friendly-id-jackson2-datatype</artifactId>
13+
14+
<name>FriendlyId Jackson 2.x Datatype</name>
15+
<description>Jackson 2.x module for JSON serialization/deserialization of UUIDs as FriendlyIds</description>
16+
17+
<properties>
18+
<jackson2.version>2.18.2</jackson2.version>
19+
</properties>
20+
21+
<dependencies>
22+
<dependency>
23+
<groupId>com.devskiller.friendly-id</groupId>
24+
<artifactId>friendly-id</artifactId>
25+
<version>${project.version}</version>
26+
</dependency>
27+
<dependency>
28+
<groupId>com.fasterxml.jackson.core</groupId>
29+
<artifactId>jackson-annotations</artifactId>
30+
<version>${jackson2.version}</version>
31+
</dependency>
32+
<dependency>
33+
<groupId>com.fasterxml.jackson.core</groupId>
34+
<artifactId>jackson-core</artifactId>
35+
<version>${jackson2.version}</version>
36+
</dependency>
37+
<dependency>
38+
<groupId>com.fasterxml.jackson.core</groupId>
39+
<artifactId>jackson-databind</artifactId>
40+
<version>${jackson2.version}</version>
41+
</dependency>
42+
<dependency>
43+
<groupId>com.fasterxml.jackson.module</groupId>
44+
<artifactId>jackson-module-parameter-names</artifactId>
45+
<version>${jackson2.version}</version>
46+
</dependency>
47+
48+
<dependency>
49+
<groupId>org.junit.jupiter</groupId>
50+
<artifactId>junit-jupiter</artifactId>
51+
<scope>test</scope>
52+
</dependency>
53+
<dependency>
54+
<groupId>org.assertj</groupId>
55+
<artifactId>assertj-core</artifactId>
56+
<scope>test</scope>
57+
</dependency>
58+
</dependencies>
59+
60+
<build>
61+
<plugins>
62+
<plugin>
63+
<groupId>org.apache.maven.plugins</groupId>
64+
<artifactId>maven-compiler-plugin</artifactId>
65+
<configuration>
66+
<parameters>true</parameters>
67+
</configuration>
68+
</plugin>
69+
</plugins>
70+
</build>
71+
</project>
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
package com.devskiller.friendly_id.jackson;
2+
3+
import java.util.UUID;
4+
5+
import com.fasterxml.jackson.databind.deser.std.UUIDDeserializer;
6+
import com.fasterxml.jackson.databind.introspect.Annotated;
7+
import com.fasterxml.jackson.databind.introspect.AnnotatedMethod;
8+
import com.fasterxml.jackson.databind.introspect.JacksonAnnotationIntrospector;
9+
import com.fasterxml.jackson.databind.ser.std.UUIDSerializer;
10+
11+
public class FriendlyIdAnnotationIntrospector extends JacksonAnnotationIntrospector {
12+
13+
private static final long serialVersionUID = 1L;
14+
15+
@Override
16+
public Object findSerializer(Annotated annotatedMethod) {
17+
IdFormat annotation = _findAnnotation(annotatedMethod, IdFormat.class);
18+
if (annotatedMethod.getRawType() == UUID.class) {
19+
if (annotation != null) {
20+
switch (annotation.value()) {
21+
case RAW:
22+
return UUIDSerializer.class;
23+
case URL62:
24+
return FriendlyIdSerializer.class;
25+
}
26+
}
27+
return FriendlyIdSerializer.class;
28+
} else {
29+
return null;
30+
}
31+
}
32+
33+
@Override
34+
public Object findDeserializer(Annotated annotatedMethod) {
35+
IdFormat annotation = _findAnnotation(annotatedMethod, IdFormat.class);
36+
if (rawDeserializationType(annotatedMethod) == UUID.class) {
37+
if (annotation != null) {
38+
switch (annotation.value()) {
39+
case RAW:
40+
return UUIDDeserializer.class;
41+
case URL62:
42+
return FriendlyIdDeserializer.class;
43+
}
44+
}
45+
return FriendlyIdDeserializer.class;
46+
} else {
47+
return null;
48+
}
49+
}
50+
51+
private Class<?> rawDeserializationType(Annotated a) {
52+
if (a instanceof AnnotatedMethod) {
53+
AnnotatedMethod am = (AnnotatedMethod) a;
54+
if (am.getParameterCount() == 1) {
55+
return am.getRawParameterType(0);
56+
}
57+
}
58+
return a.getRawType();
59+
}
60+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
package com.devskiller.friendly_id.jackson;
2+
3+
import java.io.IOException;
4+
import java.util.UUID;
5+
6+
import com.fasterxml.jackson.core.JsonParser;
7+
import com.fasterxml.jackson.core.JsonToken;
8+
import com.fasterxml.jackson.databind.DeserializationContext;
9+
import com.fasterxml.jackson.databind.deser.std.UUIDDeserializer;
10+
11+
import com.devskiller.friendly_id.FriendlyId;
12+
13+
public class FriendlyIdDeserializer extends UUIDDeserializer {
14+
15+
@Override
16+
public UUID deserialize(JsonParser parser, DeserializationContext deserializationContext) throws IOException {
17+
18+
JsonToken token = parser.getCurrentToken();
19+
if (token == JsonToken.VALUE_STRING) {
20+
String string = parser.getValueAsString().trim();
21+
if (looksLikeUuid(string)) {
22+
return super.deserialize(parser, deserializationContext);
23+
} else {
24+
return FriendlyId.toUuid(string);
25+
}
26+
}
27+
throw new IllegalStateException("This is not friendly id");
28+
}
29+
30+
private boolean looksLikeUuid(String value) {
31+
return value.contains("-");
32+
}
33+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
package com.devskiller.friendly_id.jackson;
2+
3+
/**
4+
* Friendly ID format
5+
*/
6+
public enum FriendlyIdFormat {
7+
8+
/**
9+
* Url62 encoded ID
10+
*/
11+
URL62,
12+
13+
/**
14+
* Leave this ID as is (without conversion)
15+
*/
16+
RAW
17+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
package com.devskiller.friendly_id.jackson;
2+
3+
import java.util.UUID;
4+
5+
import com.fasterxml.jackson.databind.module.SimpleModule;
6+
7+
public class FriendlyIdModule extends SimpleModule {
8+
9+
private FriendlyIdAnnotationIntrospector introspector;
10+
11+
public FriendlyIdModule() {
12+
introspector = new FriendlyIdAnnotationIntrospector();
13+
addDeserializer(UUID.class, new FriendlyIdDeserializer());
14+
addSerializer(UUID.class, new FriendlyIdSerializer());
15+
16+
// Add serializer/deserializer for FriendlyId value object
17+
addDeserializer(com.devskiller.friendly_id.type.FriendlyId.class, new FriendlyIdValueDeserializer());
18+
addSerializer(com.devskiller.friendly_id.type.FriendlyId.class, new FriendlyIdValueSerializer());
19+
}
20+
21+
@Override
22+
public void setupModule(SetupContext context) {
23+
super.setupModule(context);
24+
context.insertAnnotationIntrospector(introspector);
25+
}
26+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
package com.devskiller.friendly_id.jackson;
2+
3+
import java.io.IOException;
4+
import java.util.UUID;
5+
6+
import com.fasterxml.jackson.core.JsonGenerator;
7+
import com.fasterxml.jackson.databind.SerializerProvider;
8+
import com.fasterxml.jackson.databind.ser.std.StdSerializer;
9+
10+
import com.devskiller.friendly_id.FriendlyId;
11+
12+
public class FriendlyIdSerializer extends StdSerializer<UUID> {
13+
14+
public FriendlyIdSerializer() {
15+
super(UUID.class);
16+
}
17+
18+
@Override
19+
public void serialize(UUID uuid, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {
20+
jsonGenerator.writeString(FriendlyId.toFriendlyId(uuid));
21+
}
22+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
package com.devskiller.friendly_id.jackson;
2+
3+
import java.io.IOException;
4+
5+
import com.fasterxml.jackson.core.JsonParser;
6+
import com.fasterxml.jackson.databind.DeserializationContext;
7+
import com.fasterxml.jackson.databind.JsonDeserializer;
8+
9+
import com.devskiller.friendly_id.type.FriendlyId;
10+
11+
/**
12+
* JSON deserializer for {@link FriendlyId} value object.
13+
* Deserializes JSON strings to FriendlyId instances.
14+
*/
15+
public class FriendlyIdValueDeserializer extends JsonDeserializer<FriendlyId> {
16+
17+
@Override
18+
public FriendlyId deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
19+
String friendlyIdString = p.getValueAsString();
20+
return FriendlyId.fromString(friendlyIdString);
21+
}
22+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
package com.devskiller.friendly_id.jackson;
2+
3+
import java.io.IOException;
4+
5+
import com.fasterxml.jackson.core.JsonGenerator;
6+
import com.fasterxml.jackson.databind.JsonSerializer;
7+
import com.fasterxml.jackson.databind.SerializerProvider;
8+
9+
import com.devskiller.friendly_id.type.FriendlyId;
10+
11+
/**
12+
* JSON serializer for {@link FriendlyId} value object.
13+
* Serializes FriendlyId instances as their string representation.
14+
*/
15+
public class FriendlyIdValueSerializer extends JsonSerializer<FriendlyId> {
16+
17+
@Override
18+
public void serialize(FriendlyId value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
19+
gen.writeString(value.toString());
20+
}
21+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
package com.devskiller.friendly_id.jackson;
2+
3+
import java.lang.annotation.Retention;
4+
import java.lang.annotation.RetentionPolicy;
5+
6+
/**
7+
* Declares that a field should be formatted as a friendly ID.
8+
*/
9+
@Retention(RetentionPolicy.RUNTIME)
10+
public @interface IdFormat {
11+
12+
FriendlyIdFormat value() default FriendlyIdFormat.URL62;
13+
14+
}

0 commit comments

Comments
 (0)