Skip to content

Commit cb40ddf

Browse files
committed
add swagger customizers
1 parent d243cef commit cb40ddf

10 files changed

Lines changed: 367 additions & 25 deletions

pom.xml

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
<parent>
77
<groupId>org.springframework.boot</groupId>
88
<artifactId>spring-boot-starter-parent</artifactId>
9-
<version>3.3.2</version>
9+
<version>3.3.3</version>
1010
<relativePath/> <!-- lookup parent from repository -->
1111
</parent>
1212

@@ -76,6 +76,12 @@
7676
<version>4.4</version>
7777
</dependency>
7878

79+
<!-- Swagger -->
80+
<dependency>
81+
<groupId>org.springdoc</groupId>
82+
<artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
83+
<version>2.6.0</version>
84+
</dependency>
7985

8086
<!-- Testing -->
8187
<dependency>
@@ -89,7 +95,7 @@
8995
<plugin>
9096
<groupId>org.apache.maven.plugins</groupId>
9197
<artifactId>maven-compiler-plugin</artifactId>
92-
<version>3.11.0</version>
98+
<version>3.13.0</version>
9399
<configuration>
94100
<source>${java.version}</source>
95101
<target>${java.version}</target>
@@ -98,7 +104,7 @@
98104
<plugin>
99105
<groupId>org.apache.maven.plugins</groupId>
100106
<artifactId>maven-checkstyle-plugin</artifactId>
101-
<version>3.2.1</version>
107+
<version>3.5.0</version>
102108
<configuration>
103109
<configLocation>checkstyle.xml</configLocation>
104110
<suppressionsFileExpression>
@@ -122,7 +128,7 @@
122128
<dependency>
123129
<groupId>com.puppycrawl.tools</groupId>
124130
<artifactId>checkstyle</artifactId>
125-
<version>10.3.4</version>
131+
<version>10.18.1</version>
126132
</dependency>
127133
</dependencies>
128134
</plugin>

src/main/java/it/aboutbits/springboot/toolbox/boot/type/RegisterCustomTypes.java

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
package it.aboutbits.springboot.toolbox.boot.type;
22

3+
import it.aboutbits.springboot.toolbox.boot.type.swagger.GenericSingleValueWrapperModelConverter;
4+
import it.aboutbits.springboot.toolbox.boot.type.swagger.GenericSingleValueWrapperPropertyCustomizer;
5+
import it.aboutbits.springboot.toolbox.boot.type.swagger.IdentityModelConverter;
6+
import it.aboutbits.springboot.toolbox.boot.type.swagger.IdentityPropertyCustomizer;
37
import org.springframework.context.annotation.Import;
48

59
import java.lang.annotation.ElementType;
@@ -9,7 +13,13 @@
913

1014
@Target({ElementType.TYPE})
1115
@Retention(RetentionPolicy.RUNTIME)
12-
@Import({CustomTypeConfigurationRegistrar.class})
16+
@Import({
17+
GenericSingleValueWrapperModelConverter.class,
18+
GenericSingleValueWrapperPropertyCustomizer.class,
19+
IdentityModelConverter.class,
20+
IdentityPropertyCustomizer.class,
21+
CustomTypeConfigurationRegistrar.class
22+
})
1323
public @interface RegisterCustomTypes {
1424
String[] additionalTypePackages() default "";
1525
}
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
package it.aboutbits.springboot.toolbox.boot.type.swagger;
2+
3+
import io.swagger.v3.core.converter.AnnotatedType;
4+
import io.swagger.v3.core.converter.ModelConverter;
5+
import io.swagger.v3.core.converter.ModelConverterContext;
6+
import io.swagger.v3.oas.models.media.Schema;
7+
import it.aboutbits.springboot.toolbox.persistence.identity.EntityId;
8+
import it.aboutbits.springboot.toolbox.reflection.util.RecordReflectionUtil;
9+
import it.aboutbits.springboot.toolbox.type.CustomType;
10+
import org.springframework.stereotype.Component;
11+
12+
import java.math.BigDecimal;
13+
import java.util.Iterator;
14+
15+
@Component
16+
public class GenericSingleValueWrapperModelConverter implements ModelConverter {
17+
18+
@Override
19+
public Schema<?> resolve(
20+
AnnotatedType annotatedType,
21+
ModelConverterContext context,
22+
Iterator<ModelConverter> chain
23+
) {
24+
25+
var type = annotatedType.getType();
26+
27+
if (type instanceof Class<?> clazz && CustomType.class.isAssignableFrom(clazz) && !EntityId.class.isAssignableFrom(
28+
clazz)) {
29+
var constructor = RecordReflectionUtil.getCanonicalConstructor(clazz);
30+
var wrappedType = constructor.getParameters()[0].getType();
31+
32+
if (Short.class.isAssignableFrom(wrappedType)) {
33+
return context.resolve(new AnnotatedType(Short.TYPE));
34+
}
35+
if (Integer.class.isAssignableFrom(wrappedType)) {
36+
return context.resolve(new AnnotatedType(Integer.TYPE));
37+
}
38+
if (Long.class.isAssignableFrom(wrappedType)) {
39+
return context.resolve(new AnnotatedType(Long.TYPE));
40+
}
41+
if (Float.class.isAssignableFrom(wrappedType)) {
42+
return context.resolve(new AnnotatedType(Float.TYPE));
43+
}
44+
if (Double.class.isAssignableFrom(wrappedType)) {
45+
return context.resolve(new AnnotatedType(Double.TYPE));
46+
}
47+
if (BigDecimal.class.isAssignableFrom(wrappedType)) {
48+
return context.resolve(new AnnotatedType(Double.TYPE));
49+
}
50+
if (String.class.isAssignableFrom(wrappedType)) {
51+
return context.resolve(new AnnotatedType(String.class));
52+
}
53+
}
54+
55+
return chain.hasNext() ? chain.next().resolve(annotatedType, context, chain) : null;
56+
}
57+
}
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
package it.aboutbits.springboot.toolbox.boot.type.swagger;
2+
3+
import com.fasterxml.jackson.databind.type.SimpleType;
4+
import io.swagger.v3.core.converter.AnnotatedType;
5+
import io.swagger.v3.oas.models.media.Schema;
6+
import it.aboutbits.springboot.toolbox.persistence.identity.EntityId;
7+
import it.aboutbits.springboot.toolbox.reflection.util.RecordReflectionUtil;
8+
import it.aboutbits.springboot.toolbox.type.CustomType;
9+
import lombok.extern.slf4j.Slf4j;
10+
import org.springdoc.core.customizers.PropertyCustomizer;
11+
import org.springframework.stereotype.Component;
12+
13+
import java.math.BigDecimal;
14+
15+
@Slf4j
16+
@Component
17+
public class GenericSingleValueWrapperPropertyCustomizer implements PropertyCustomizer {
18+
@Override
19+
public Schema<?> customize(Schema property, AnnotatedType annotatedType) {
20+
var type = annotatedType.getType();
21+
22+
if (type instanceof SimpleType simpleType && CustomType.class.isAssignableFrom(simpleType.getRawClass()) && !EntityId.class.isAssignableFrom(
23+
simpleType.getRawClass())) {
24+
var rawClass = simpleType.getRawClass();
25+
26+
var displayName = rawClass.getSimpleName();
27+
28+
var constructor = RecordReflectionUtil.getCanonicalConstructor(rawClass);
29+
var wrappedType = constructor.getParameters()[0].getType();
30+
31+
32+
if (Short.class.isAssignableFrom(wrappedType)) {
33+
property.type("integer");
34+
property.format("");
35+
property.setDescription(displayName);
36+
property.setProperties(null);
37+
property.set$ref(null);
38+
return property;
39+
}
40+
if (Integer.class.isAssignableFrom(wrappedType)) {
41+
property.type("integer");
42+
property.format("int32");
43+
property.setDescription(displayName);
44+
property.setProperties(null);
45+
property.set$ref(null);
46+
return property;
47+
}
48+
if (Long.class.isAssignableFrom(wrappedType)) {
49+
property.type("integer");
50+
property.format("int64");
51+
property.setDescription(displayName);
52+
property.setProperties(null);
53+
property.set$ref(null);
54+
return property;
55+
}
56+
if (Float.class.isAssignableFrom(wrappedType)) {
57+
property.type("number");
58+
property.format("float");
59+
property.setDescription(displayName);
60+
property.setProperties(null);
61+
property.set$ref(null);
62+
return property;
63+
}
64+
if (Double.class.isAssignableFrom(wrappedType)) {
65+
property.type("number");
66+
property.format("double");
67+
property.setDescription(displayName);
68+
property.setProperties(null);
69+
property.set$ref(null);
70+
return property;
71+
}
72+
if (BigDecimal.class.isAssignableFrom(wrappedType)) {
73+
property.type("number");
74+
property.format("");
75+
property.setDescription(displayName);
76+
property.setProperties(null);
77+
property.set$ref(null);
78+
return property;
79+
}
80+
if (String.class.isAssignableFrom(wrappedType)) {
81+
property.type("string");
82+
property.format(null);
83+
property.setDescription(displayName);
84+
property.setProperties(null);
85+
property.set$ref(null);
86+
return property;
87+
}
88+
log.warn("Property {} of type WrappedValue: Can not resolve parameter type!", property.getName());
89+
}
90+
91+
return property;
92+
}
93+
}
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
package it.aboutbits.springboot.toolbox.boot.type.swagger;
2+
3+
import io.swagger.v3.core.converter.AnnotatedType;
4+
import io.swagger.v3.core.converter.ModelConverter;
5+
import io.swagger.v3.core.converter.ModelConverterContext;
6+
import io.swagger.v3.oas.models.media.Schema;
7+
import it.aboutbits.springboot.toolbox.persistence.identity.EntityId;
8+
import it.aboutbits.springboot.toolbox.reflection.util.RecordReflectionUtil;
9+
import org.springframework.stereotype.Component;
10+
11+
import java.math.BigDecimal;
12+
import java.util.Iterator;
13+
14+
@Component
15+
public class IdentityModelConverter implements ModelConverter {
16+
17+
@Override
18+
public Schema<?> resolve(
19+
AnnotatedType annotatedType,
20+
ModelConverterContext context,
21+
Iterator<ModelConverter> chain
22+
) {
23+
24+
var type = annotatedType.getType();
25+
26+
if (type instanceof Class<?> clazz && EntityId.class.isAssignableFrom(clazz)) {
27+
var constructor = RecordReflectionUtil.getCanonicalConstructor(clazz);
28+
29+
var wrappedType = constructor.getParameters()[0].getType();
30+
31+
if (Short.class.isAssignableFrom(wrappedType)) {
32+
return context.resolve(new AnnotatedType(Short.TYPE));
33+
}
34+
if (Integer.class.isAssignableFrom(wrappedType)) {
35+
return context.resolve(new AnnotatedType(Integer.TYPE));
36+
}
37+
if (Long.class.isAssignableFrom(wrappedType)) {
38+
return context.resolve(new AnnotatedType(Long.TYPE));
39+
}
40+
if (Float.class.isAssignableFrom(wrappedType)) {
41+
return context.resolve(new AnnotatedType(Float.TYPE));
42+
}
43+
if (Double.class.isAssignableFrom(wrappedType)) {
44+
return context.resolve(new AnnotatedType(Double.TYPE));
45+
}
46+
if (BigDecimal.class.isAssignableFrom(wrappedType)) {
47+
return context.resolve(new AnnotatedType(Double.TYPE));
48+
}
49+
if (String.class.isAssignableFrom(wrappedType)) {
50+
return context.resolve(new AnnotatedType(String.class));
51+
}
52+
}
53+
54+
return chain.hasNext() ? chain.next().resolve(annotatedType, context, chain) : null;
55+
}
56+
}
Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
package it.aboutbits.springboot.toolbox.boot.type.swagger;
2+
3+
import com.fasterxml.jackson.databind.type.SimpleType;
4+
import io.swagger.v3.core.converter.AnnotatedType;
5+
import io.swagger.v3.oas.models.media.Schema;
6+
import it.aboutbits.springboot.toolbox.persistence.identity.EntityId;
7+
import it.aboutbits.springboot.toolbox.reflection.util.RecordReflectionUtil;
8+
import lombok.NonNull;
9+
import lombok.extern.slf4j.Slf4j;
10+
import org.springdoc.core.customizers.PropertyCustomizer;
11+
import org.springframework.stereotype.Component;
12+
13+
import java.math.BigDecimal;
14+
15+
@Slf4j
16+
@Component
17+
public class IdentityPropertyCustomizer implements PropertyCustomizer {
18+
@Override
19+
public Schema<?> customize(Schema property, AnnotatedType annotatedType) {
20+
var type = annotatedType.getType();
21+
22+
if (type instanceof SimpleType simpleType && EntityId.class.isAssignableFrom(simpleType.getRawClass())) {
23+
String displayName = null;
24+
25+
var bindings = simpleType.getBindings();
26+
var boundType = bindings.getBoundType(0);
27+
28+
if (boundType == null) {
29+
var rawClass = simpleType.getRawClass();
30+
displayName = resolveDisplayName(rawClass);
31+
}
32+
33+
var constructor = RecordReflectionUtil.getCanonicalConstructor(simpleType.getRawClass());
34+
35+
var wrappedType = constructor.getParameters()[0].getType();
36+
37+
38+
if (Short.class.isAssignableFrom(wrappedType)) {
39+
property.type("integer");
40+
property.format("");
41+
property.setDescription(displayName);
42+
property.setProperties(null);
43+
property.set$ref(null);
44+
return property;
45+
}
46+
if (Integer.class.isAssignableFrom(wrappedType)) {
47+
property.type("integer");
48+
property.format("int32");
49+
property.setDescription(displayName);
50+
property.setProperties(null);
51+
property.set$ref(null);
52+
return property;
53+
}
54+
if (Long.class.isAssignableFrom(wrappedType)) {
55+
property.type("integer");
56+
property.format("int64");
57+
property.setDescription(displayName);
58+
property.setProperties(null);
59+
property.set$ref(null);
60+
return property;
61+
}
62+
if (Float.class.isAssignableFrom(wrappedType)) {
63+
property.type("number");
64+
property.format("float");
65+
property.setDescription(displayName);
66+
property.setProperties(null);
67+
property.set$ref(null);
68+
return property;
69+
}
70+
if (Double.class.isAssignableFrom(wrappedType)) {
71+
property.type("number");
72+
property.format("double");
73+
property.setDescription(displayName);
74+
property.setProperties(null);
75+
property.set$ref(null);
76+
return property;
77+
}
78+
if (BigDecimal.class.isAssignableFrom(wrappedType)) {
79+
property.type("number");
80+
property.format("");
81+
property.setDescription(displayName);
82+
property.setProperties(null);
83+
property.set$ref(null);
84+
return property;
85+
}
86+
if (String.class.isAssignableFrom(wrappedType)) {
87+
property.type("string");
88+
property.format(null);
89+
property.setDescription(displayName);
90+
property.setProperties(null);
91+
property.set$ref(null);
92+
return property;
93+
}
94+
log.warn("Property {} of type EntityId: Can not resolve parameter type!", property.getName());
95+
}
96+
97+
return property;
98+
}
99+
100+
@NonNull
101+
private static String resolveDisplayName(Class<?> rawClass) {
102+
var parent = rawClass.getEnclosingClass();
103+
if (parent != null) {
104+
return parent.getSimpleName() + "." + rawClass.getSimpleName();
105+
}
106+
return rawClass.getSimpleName();
107+
}
108+
}

src/main/java/it/aboutbits/springboot/toolbox/persistence/identity/Identity.java renamed to src/main/java/it/aboutbits/springboot/toolbox/persistence/identity/EntityId.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,5 +10,5 @@
1010
*
1111
* @param <T> the type of the value being wrapped
1212
*/
13-
public interface Identity<T> extends CustomType<T>, Serializable {
13+
public interface EntityId<T> extends CustomType<T>, Serializable {
1414
}

0 commit comments

Comments
 (0)