适配swagger枚举类型的数据展示方式,不要只展示枚举字段的名称
@Component
public class ApiEnumPropertyBuilder implements ModelPropertyBuilderPlugin {
/** Descriptions */
private final DescriptionResolver descriptions;
/** Model specifications */
private final ModelSpecificationFactory modelSpecifications;
/**
* Api enum property reference builder
*
* @param descriptions descriptions
* @param modelSpecifications model specifications
* @since 1.0.0
*/
public ApiEnumPropertyBuilder(
DescriptionResolver descriptions,
ModelSpecificationFactory modelSpecifications) {
this.descriptions = descriptions;
this.modelSpecifications = modelSpecifications;
}
/**
* 定义model的字段解析
*
* @param context context
* @since 1.0.0
*/
@Override
public void apply(ModelPropertyContext context) {
Optional<ApiEnumProperty> annotation = empty();
Optional<BeanPropertyDefinition> definition = context.getBeanPropertyDefinition();
if (!definition.isPresent()) {
return;
}
if (context.getAnnotatedElement().isPresent()) {
annotation =
annotation.map(Optional::of)
.orElse(findApiModePropertyAnnotation(context.getAnnotatedElement().get()));
}
annotation = annotation.map(Optional::of).orElse(findPropertyAnnotation(
definition.get(),
ApiEnumProperty.class));
BeanPropertyDefinition propertyDefinition = definition.get();
Class<?> type = propertyDefinition.getRawPrimaryType();
if (annotation.isPresent()) {
this.extractByAnnotation(context, annotation);
return;
}
if (SerializeEnum.class.isAssignableFrom(type)) {
this.extractByType(context, type);
}
}
/**
* Extract by type
*
* @param context context
* @param type type
* @since 1.0.0
*/
private void extractByType(ModelPropertyContext context, Class<?> type) {
context.getSpecificationBuilder()
.enumerationFacet(e -> e.allowedValues(toAllowableValues(type)));
context.getBuilder()
.allowableValues(toAllowableValues(type));
}
/**
* Extracted
*
* @param context context
* @param annotation annotation
* @since 1.0.0
*/
private void extractByAnnotation(ModelPropertyContext context, Optional<ApiEnumProperty> annotation) {
ModelSpecification modelSpecification =
annotation.map(a -> {
if (a.enumClz() != Enum.class) {
return this.modelSpecifications
.create(context.getOwner(), toType(context.getResolver()).apply(a));
}
return null;
})
.orElse(null);
ApiEnumProperty enumPropertyReference = annotation.get();
Class<? extends Enum> enumClz = enumPropertyReference.enumClz();
context.getSpecificationBuilder()
.description(annotation.map(toDescription(this.descriptions)).orElse(null))
.isHidden(annotation.map(ApiEnumProperty::hidden).orElse(false))
.type(modelSpecification)
.position(annotation.map(ApiEnumProperty::position).orElse(0))
.required(annotation.map(ApiEnumProperty::required).orElse(false))
.example(annotation.map(toExample()).orElse(null))
.enumerationFacet(e -> e.allowedValues(toAllowableValues(enumClz)));
context.getBuilder()
.allowableValues(toAllowableValues(enumClz))
.required(annotation.map(ApiEnumProperty::required).orElse(false))
.description(annotation.map(toDescription(this.descriptions)).orElse(null))
.isHidden(annotation.map(ApiEnumProperty::hidden).orElse(false))
.type(annotation.map(toType(context.getResolver())).orElse(null))
.position(annotation.map(ApiEnumProperty::position).orElse(0))
.example(annotation.map(toExample()).orElse(null));
}
/**
* Supports
*
* @param documentationType documentation type
* @return the boolean
* @since 1.0.0
*/
@Override
public boolean supports(DocumentationType documentationType) {
return true;
}
/**
* Find api mode property annotation
*
* @param annotated annotated
* @return the optional
* @since 1.0.0
*/
public static Optional<ApiEnumProperty> findApiModePropertyAnnotation(AnnotatedElement annotated) {
Optional<ApiEnumProperty> annotation = empty();
if (annotated instanceof Method) {
annotation = ofNullable(AnnotationUtils.findAnnotation(((Method) annotated), ApiEnumProperty.class));
}
return annotation.map(Optional::of).orElse(ofNullable(AnnotationUtils.getAnnotation(annotated,
ApiEnumProperty.class)));
}
/**
* To type
*
* @param resolver resolver
* @return the function
* @since 1.0.0
*/
public static Function<ApiEnumProperty, ResolvedType> toType(final TypeResolver resolver) {
return annotation -> resolver.resolve(annotation.enumClz());
}
/**
* To description
*
* @param descriptions descriptions
* @return the function
* @since 1.0.0
*/
public static Function<ApiEnumProperty, String> toDescription(
final DescriptionResolver descriptions) {
return annotation -> {
String description = "";
if (!isEmpty(annotation.value())) {
description = annotation.value();
} else if (!isEmpty(annotation.notes())) {
description = annotation.notes();
}
return descriptions.resolve(description);
};
}
/**
* To example
*
* @return the function
* @since 1.0.0
*/
public static Function<ApiEnumProperty, String> toExample() {
return annotation -> {
String example = "";
if (!isEmpty(annotation.example())) {
example = annotation.example();
}
return example;
};
}
/**
* To allowable values
*
* @param type type
* @return the function
* @since 1.0.0
*/
@SuppressWarnings("all")
public static AllowableValues toAllowableValues(Class<?> type) {
List<String> list = new ArrayList<>();
if (SerializeEnum.class.isAssignableFrom(type)) {
Class<SerializeEnum<?>> serializeEnumClass = (Class<SerializeEnum<?>>) type;
SerializeEnum<?>[] constants = serializeEnumClass.getEnumConstants();
if (constants != null) {
Stream.of(constants)
.forEach(item -> list.add(String.format("(%s,%s)", item.getValue(), item.getDesc())));
}
} else {
Class<? extends Enum> enumClz = (Class<? extends Enum>) type;
Enum[] enumConstants = enumClz.getEnumConstants();
if (enumConstants != null) {
Stream.of(enumConstants)
.forEach(item -> list.add(String.format("(%d,%s)", item.ordinal(), item.name())));
}
}
AllowableListValues values = new AllowableListValues(Collections.unmodifiableList(list), "LIST");
return values;
}
}
自定义枚举属性的注解
@Target({ElementType.METHOD, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface ApiEnumProperty {
/**
* Value
*
* @return the string
* @since 1.0.0
*/
String value();
/**
* Enum clz
*
* @return the class
* @since 1.0.0
*/
Class<? extends Enum> enumClz() default Enum.class;
/**
* Name
*
* @return the string
* @since 1.0.0
*/
String name() default "";
/**
* Access
*
* @return the string
* @since 1.0.0
*/
String access() default "";
/**
* Notes
*
* @return the string
* @since 1.0.0
*/
String notes() default "";
/**
* Required
*
* @return the boolean
* @since 1.0.0
*/
boolean required() default false;
/**
* Position
*
* @return the int
* @since 1.0.0
*/
int position() default 0;
/**
* Hidden
*
* @return the boolean
* @since 1.0.0
*/
boolean hidden() default false;
/**
* Example
*
* @return the string
* @since 1.0.0
*/
String example() default "";
}