Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package it.aboutbits.springboot.toolbox.swagger;

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Getter;
import lombok.Setter;

@Getter
@Setter
@JsonInclude(JsonInclude.Include.NON_NULL)
public class SwaggerMeta {
private String originalTypeFqn = null;
@JsonProperty("isIdentity")
private Boolean isIdentity = null;
@JsonProperty("isNestedStructure")
private Boolean isNestedStructure = null;
@JsonProperty("isMap")
private Boolean isMap = null;
private String mapKeyTypeFqn = null;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
package it.aboutbits.springboot.toolbox.swagger;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.NonNull;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.lang.Nullable;

@Slf4j
public final class SwaggerMetaUtil {
private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();

private SwaggerMetaUtil() {
}

@SneakyThrows(JsonProcessingException.class)
public static String setMapKeyTypeFqn(@Nullable String currentMeta, @NonNull String value) {
var meta = getSwaggerMeta(currentMeta);
meta.setMapKeyTypeFqn(value);

return OBJECT_MAPPER.writeValueAsString(meta);
}

@SneakyThrows(JsonProcessingException.class)
public static String setIsMap(@Nullable String currentMeta, boolean value) {
var meta = getSwaggerMeta(currentMeta);
meta.setIsMap(!value ? null : true);

return OBJECT_MAPPER.writeValueAsString(meta);
}

@SneakyThrows(JsonProcessingException.class)
public static String setOriginalTypeFqn(@Nullable String currentMeta, @NonNull String value) {
var meta = getSwaggerMeta(currentMeta);
meta.setOriginalTypeFqn(value);

return OBJECT_MAPPER.writeValueAsString(meta);
}

@SneakyThrows(JsonProcessingException.class)
public static String setIsIdentity(@Nullable String currentMeta, boolean value) {
var meta = getSwaggerMeta(currentMeta);
meta.setIsIdentity(!value ? null : true);

return OBJECT_MAPPER.writeValueAsString(meta);
}

@SneakyThrows(JsonProcessingException.class)
public static String setIsNestedStructure(@Nullable String currentMeta, boolean value) {
var meta = getSwaggerMeta(currentMeta);
meta.setIsNestedStructure(!value ? null : true);

return OBJECT_MAPPER.writeValueAsString(meta);
}

private static SwaggerMeta getSwaggerMeta(String currentMeta) {
var meta = new SwaggerMeta();
if (currentMeta != null) {
try {
meta = OBJECT_MAPPER.readValue(currentMeta, SwaggerMeta.class);
} catch (JsonProcessingException e) {
log.warn("error processing meta for swagger: {}", currentMeta);
}
}
return meta;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,10 @@
import io.swagger.v3.core.converter.ModelConverterContext;
import io.swagger.v3.oas.models.media.Schema;
import it.aboutbits.springboot.toolbox.reflection.util.RecordReflectionUtil;
import it.aboutbits.springboot.toolbox.swagger.SwaggerMetaUtil;
import it.aboutbits.springboot.toolbox.type.CustomType;
import it.aboutbits.springboot.toolbox.type.ScaledBigDecimal;
import it.aboutbits.springboot.toolbox.type.identity.EntityId;

import java.math.BigDecimal;
import java.math.BigInteger;
Expand All @@ -23,36 +25,52 @@ public Schema<?> resolve(

var type = annotatedType.getType();

if (type instanceof Class<?> clazz && CustomType.class.isAssignableFrom(clazz)) {
var constructor = RecordReflectionUtil.getCanonicalConstructor(clazz);
var wrappedType = constructor.getParameters()[0].getType();
if (type instanceof Class<?> clazz) {
Schema<?> result = null;
if (CustomType.class.isAssignableFrom(clazz)) {
var constructor = RecordReflectionUtil.getCanonicalConstructor(clazz);
var wrappedType = constructor.getParameters()[0].getType();

if (Short.class.isAssignableFrom(wrappedType)) {
return context.resolve(new AnnotatedType(Short.TYPE));
}
if (Integer.class.isAssignableFrom(wrappedType)) {
return context.resolve(new AnnotatedType(Integer.TYPE));
}
if (Long.class.isAssignableFrom(wrappedType)) {
return context.resolve(new AnnotatedType(Long.TYPE));
}
if (BigInteger.class.isAssignableFrom(wrappedType)) {
return context.resolve(new AnnotatedType(Long.TYPE));
}
if (Float.class.isAssignableFrom(wrappedType)) {
return context.resolve(new AnnotatedType(Float.TYPE));
}
if (Double.class.isAssignableFrom(wrappedType)) {
return context.resolve(new AnnotatedType(Double.TYPE));
}
if (BigDecimal.class.isAssignableFrom(wrappedType)) {
return context.resolve(new AnnotatedType(Double.TYPE));
}
if (ScaledBigDecimal.class.isAssignableFrom(wrappedType)) {
return context.resolve(new AnnotatedType(Double.TYPE));
}
if (String.class.isAssignableFrom(wrappedType)) {
return context.resolve(new AnnotatedType(String.class));
if (Short.class.isAssignableFrom(wrappedType)) {
result = context.resolve(new AnnotatedType(Short.TYPE));
}
if (Integer.class.isAssignableFrom(wrappedType)) {
result = context.resolve(new AnnotatedType(Integer.TYPE));
}
if (Long.class.isAssignableFrom(wrappedType)) {
result = context.resolve(new AnnotatedType(Long.TYPE));
}
if (BigInteger.class.isAssignableFrom(wrappedType)) {
result = context.resolve(new AnnotatedType(Long.TYPE));
}
if (Float.class.isAssignableFrom(wrappedType)) {
result = context.resolve(new AnnotatedType(Float.TYPE));
}
if (Double.class.isAssignableFrom(wrappedType)) {
result = context.resolve(new AnnotatedType(Double.TYPE));
}
if (BigDecimal.class.isAssignableFrom(wrappedType)) {
result = context.resolve(new AnnotatedType(Double.TYPE));
}
if (ScaledBigDecimal.class.isAssignableFrom(wrappedType)) {
result = context.resolve(new AnnotatedType(Double.TYPE));
}
if (String.class.isAssignableFrom(wrappedType)) {
result = context.resolve(new AnnotatedType(String.class));
}

if (result != null) {
var isIdentity = EntityId.class.isAssignableFrom(clazz);

var description = SwaggerMetaUtil.setOriginalTypeFqn(
result.getDescription(),
((Class<?>) type).getName()
);
description = SwaggerMetaUtil.setIsIdentity(description, isIdentity);
result.setDescription(description);

return result;
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@
import io.swagger.v3.core.converter.AnnotatedType;
import io.swagger.v3.oas.models.media.Schema;
import it.aboutbits.springboot.toolbox.reflection.util.RecordReflectionUtil;
import it.aboutbits.springboot.toolbox.swagger.SwaggerMetaUtil;
import it.aboutbits.springboot.toolbox.type.CustomType;
import it.aboutbits.springboot.toolbox.type.ScaledBigDecimal;
import it.aboutbits.springboot.toolbox.type.identity.EntityId;
import lombok.NonNull;
import lombok.extern.slf4j.Slf4j;
import org.springdoc.core.customizers.PropertyCustomizer;

Expand All @@ -23,116 +23,103 @@ public Schema<?> customize(Schema property, AnnotatedType annotatedType) {
if (type instanceof SimpleType simpleType) {
var rawClass = simpleType.getRawClass();

// We set the enum name as the description because swagger treats each usage as a new enum.
// This way we can preserve the information about the original enum type.
if (rawClass.isEnum()) {
var displayName = rawClass.getCanonicalName().replace(rawClass.getPackage().getName() + ".", "");
property.setDescription(displayName);
if (rawClass.getName().contains(".") && !rawClass.getName().startsWith("java.")) {
property.setDescription(SwaggerMetaUtil.setOriginalTypeFqn(
property.getDescription(),
rawClass.getName()
));
}
}

if (type instanceof SimpleType simpleType && CustomType.class.isAssignableFrom(simpleType.getRawClass())) {
var rawClass = simpleType.getRawClass();

var displayName = rawClass.getSimpleName();
if (CustomType.class.isAssignableFrom(simpleType.getRawClass())) {
Class<?> wrappedType;
if (rawClass.equals(EntityId.class)) {
wrappedType = simpleType.getBindings().getBoundType(0).getRawClass();
} else {
var constructor = RecordReflectionUtil.getCanonicalConstructor(rawClass);
wrappedType = constructor.getParameters()[0].getType();
}

Class<?> wrappedType;
if (EntityId.class.isAssignableFrom(rawClass)) {
displayName = resolveEntityIdDisplayName(rawClass);
}
var isIdentity = EntityId.class.isAssignableFrom(rawClass);

if (rawClass.equals(EntityId.class)) {
wrappedType = simpleType.getBindings().getBoundType(0).getRawClass();
} else {
var constructor = RecordReflectionUtil.getCanonicalConstructor(rawClass);
wrappedType = constructor.getParameters()[0].getType();
}
var description = SwaggerMetaUtil.setIsIdentity(property.getDescription(), isIdentity);

if (Short.class.isAssignableFrom(wrappedType)) {
property.type("integer");
property.format("");
property.setDescription(displayName);
property.setProperties(null);
property.set$ref(null);
return property;
}
if (Integer.class.isAssignableFrom(wrappedType)) {
property.type("integer");
property.format("int32");
property.setDescription(displayName);
property.setProperties(null);
property.set$ref(null);
return property;
}
if (Long.class.isAssignableFrom(wrappedType)) {
property.type("integer");
property.format("int64");
property.setDescription(displayName);
property.setProperties(null);
property.set$ref(null);
return property;
}
if (BigInteger.class.isAssignableFrom(wrappedType)) {
property.type("integer");
property.format("int64");
property.setDescription(displayName);
property.setProperties(null);
property.set$ref(null);
return property;
}
if (Float.class.isAssignableFrom(wrappedType)) {
property.type("number");
property.format("float");
property.setDescription(displayName);
property.setProperties(null);
property.set$ref(null);
return property;
}
if (Double.class.isAssignableFrom(wrappedType)) {
property.type("number");
property.format("double");
property.setDescription(displayName);
property.setProperties(null);
property.set$ref(null);
return property;
}
if (BigDecimal.class.isAssignableFrom(wrappedType)) {
property.type("number");
property.format("");
property.setDescription(displayName);
property.setProperties(null);
property.set$ref(null);
return property;
}
if (Short.class.isAssignableFrom(wrappedType)) {
property.type("integer");
property.format("");
property.setDescription(description);
property.setProperties(null);
property.set$ref(null);
return property;
}
if (Integer.class.isAssignableFrom(wrappedType)) {
property.type("integer");
property.format("int32");
property.setDescription(description);
property.setProperties(null);
property.set$ref(null);
return property;
}
if (Long.class.isAssignableFrom(wrappedType)) {
property.type("integer");
property.format("int64");
property.setDescription(description);
property.setProperties(null);
property.set$ref(null);
return property;
}
if (BigInteger.class.isAssignableFrom(wrappedType)) {
property.type("integer");
property.format("int64");
property.setDescription(description);
property.setProperties(null);
property.set$ref(null);
return property;
}
if (Float.class.isAssignableFrom(wrappedType)) {
property.type("number");
property.format("float");
property.setDescription(description);
property.setProperties(null);
property.set$ref(null);
return property;
}
if (Double.class.isAssignableFrom(wrappedType)) {
property.type("number");
property.format("double");
property.setDescription(description);
property.setProperties(null);
property.set$ref(null);
return property;
}
if (BigDecimal.class.isAssignableFrom(wrappedType)) {
property.type("number");
property.format("");
property.setDescription(description);
property.setProperties(null);
property.set$ref(null);
return property;
}

if (ScaledBigDecimal.class.isAssignableFrom(wrappedType)) {
property.type("number");
property.format("");
property.setDescription(displayName);
property.setProperties(null);
property.set$ref(null);
return property;
if (ScaledBigDecimal.class.isAssignableFrom(wrappedType)) {
property.type("number");
property.format("");
property.setDescription(description);
property.setProperties(null);
property.set$ref(null);
return property;
}
if (String.class.isAssignableFrom(wrappedType)) {
property.type("string");
property.format(null);
property.setDescription(description);
property.setProperties(null);
property.set$ref(null);
return property;
}
log.warn("Property {} of type WrappedValue: Can not resolve parameter type!", property.getName());
}
if (String.class.isAssignableFrom(wrappedType)) {
property.type("string");
property.format(null);
property.setDescription(displayName);
property.setProperties(null);
property.set$ref(null);
return property;
}
log.warn("Property {} of type WrappedValue: Can not resolve parameter type!", property.getName());
}

return property;
}

@NonNull
private static String resolveEntityIdDisplayName(Class<?> rawClass) {
var parent = rawClass.getEnclosingClass();
if (parent != null) {
return parent.getSimpleName() + "." + rawClass.getSimpleName();
}
return rawClass.getSimpleName();
}
}