'Hide property in a subclass of a @ParameterObject with springdoc

We are migrating from spring-fox to springdoc.

Sometimes we need to hide properties from common base classes that are used in @ParameterObjects.

With spring-fox (swagger2) this was working fine:

    public class BaseParameters {
        private String baseProperty; 
    }
    
    class CustomizedParameters extends BaseParameters {
        @Override
        @ApiParam(hidden = true)
        public String getBaseProperty() {
            return null;
        }
    }

The baseProperty doesn't show up in the api-docs

However with Springdoc this doesn't work:

@ParameterObject
public class BaseParameters {
    private String baseProperty; 
}

@ParameterObject    
class CustomizedParameters extends BaseParameters {
    @Override
    @Hidden
    public String getBaseProperty() {
        return null;
    }
}

I also tried to hide the baseProperty with @Parameter(hidden=true) and @JsonIgnore but the property stays in the specs

What am I missing? Is this not supported in springdoc? Any work-around?



Solution 1:[1]

I wrote a work-around for this problem. But the annotations must be placed in attributes of classe.

The problem is in the MethodParameterPojoExtractor that not consider the annotation (Hidden, JsonIgnore ...) of child class attribute.

The code below using Reflections force the filling with Hidden annotation in method parameters generated.

OBS: In Case that the hierarchy of child class bigger 1, probably is throw Error. Because I make this in a hurry.

@Bean
GenericParameterService parameterBuilder(PropertyResolverUtils propertyResolverUtils, Optional<WebConversionServiceProvider> optionalWebConversionServiceProvider) {
    return new GenericParameterService(propertyResolverUtils, delegatingMethodParameterCustomizer(),
                optionalWebConversionServiceProvider);
}

private Optional<DelegatingMethodParameterCustomizer> delegatingMethodParameterCustomizer() { // NOSONAR
    return Optional.of((originalMethodParam, methodParam) -> {
        if (originalMethodParam.hasParameterAnnotations()
            && originalMethodParam.hasParameterAnnotation(ParameterObject.class)
        ) {
            try {
                if (isParameterIgnore(originalMethodParam, methodParam)) {
                    Field field = FieldUtils.getDeclaredField(DelegatingMethodParameter.class, "additionalParameterAnnotations", true);
                    try {
                        field.set(methodParam, new Annotation[] {new Hidden() { // NOSONAR
                            @Override
                            public Class<? extends Annotation> annotationType() {
                                return Hidden.class;
                            }}
                        });
                    } catch (IllegalArgumentException|IllegalAccessException e) {
                        e.printStackTrace();
                    }
                }
            } catch (NoSuchFieldException | SecurityException e) {
                e.printStackTrace();
            }
        }
    });
}
    
private boolean isParameterIgnore(MethodParameter originalMethodParam, MethodParameter methodParam) throws NoSuchFieldException, SecurityException {
    String parameterName = Objects.requireNonNullElse(methodParam.getParameterName(), "");
    String fieldName = parameterName.indexOf('.') == -1 ? parameterName : parameterName.substring(0, parameterName.indexOf('.'));
    Field declaredField; 
    try {
        declaredField = originalMethodParam.getParameterType().getDeclaredField(fieldName);
    } catch (NoSuchFieldException e) {
        declaredField = originalMethodParam.getParameterType().getSuperclass().getDeclaredField(fieldName);
    }
    return Stream.of(declaredField.getAnnotations())
        .filter(annot -> List.of(Hidden.class, JsonIgnore.class).contains(annot.annotationType())).count() > 0;
}

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1