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
Expand Up @@ -7,9 +7,9 @@
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
Expand Down Expand Up @@ -90,27 +90,37 @@ protected FieldDescriptors createFieldDescriptors(Operation operation,

protected Type firstGenericType(MethodParameter param) {
Type type = param.getGenericParameterType();
if (type instanceof ParameterizedType) {
if(type instanceof TypeVariable) {
TypeVariable tv = (TypeVariable)type;
return findTypeFromTypeVariable(tv, param.getContainingClass());
} else if (type instanceof ParameterizedType) {
ParameterizedType parameterizedType = (ParameterizedType) type;
Type actualArgument = parameterizedType.getActualTypeArguments()[0];
if(actualArgument instanceof Class) {
return actualArgument;
} else if(actualArgument instanceof TypeVariable) {
TypeVariable typeVariable = (TypeVariable)actualArgument;
String variableName = typeVariable.getName();
Map<TypeVariable, Type> typeMap = GenericTypeResolver.getTypeVariableMap(param.getContainingClass());
for(TypeVariable tv : typeMap.keySet()) {
if(StringUtils.equals(tv.getName(), variableName)) {
return typeMap.get(tv);
}
}
return findTypeFromTypeVariable(typeVariable, param.getContainingClass());
}
return ((ParameterizedType) type).getActualTypeArguments()[0];
} else {
return Object.class;
}
}

protected Type findTypeFromTypeVariable(TypeVariable typeVariable, Class<?> clazz) {
Type defaultReturnValue = Object.class;

String variableName = typeVariable.getName();
Map<TypeVariable, Type> typeMap = GenericTypeResolver.getTypeVariableMap(clazz);
for(TypeVariable tv : typeMap.keySet()) {
if(StringUtils.equals(tv.getName(), variableName)) {
return typeMap.get(tv);
}
}
return defaultReturnValue;
}

protected abstract Type getType(HandlerMethod method);

protected abstract boolean shouldFailOnUndocumentedFields();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
Expand All @@ -25,6 +25,7 @@
import java.lang.reflect.GenericArrayType;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
import java.util.Map;

import capital.scalable.restdocs.jackson.FieldDescriptors;
Expand Down Expand Up @@ -83,6 +84,8 @@ protected Type getType(final HandlerMethod method) {
}
} else if (REACTOR_FLUX_CLASS.equals(returnType.getCanonicalName())) {
return (GenericArrayType) () -> firstGenericType(method.getReturnType());
} else if (method.getReturnType().getGenericParameterType() instanceof TypeVariable) {
return firstGenericType(method.getReturnType());
} else {
return returnType;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -433,7 +433,7 @@ public void comment() throws Exception {
}

@Test
public void genericSuperMethod() throws Exception{
public void genericSuperMethodCollection() throws Exception{
HandlerMethod handlerMethod = createHandlerMethod("getItemsGeneric");
mockFieldComment(Item.class, "field1", "A string");
mockFieldComment(Item.class, "field2", "A decimal");
Expand All @@ -452,6 +452,25 @@ public void genericSuperMethod() throws Exception{

}

@Test
public void genericSuperMethodSingleItem() throws Exception {
HandlerMethod handlerMethod = createHandlerMethod("getItemGeneric");
mockFieldComment(Item.class, "field1", "A string");
mockFieldComment(Item.class, "field2", "A decimal");

new JacksonResponseFieldSnippet().document(operationBuilder
.attribute(HandlerMethod.class.getName(), handlerMethod)
.attribute(ObjectMapper.class.getName(), mapper)
.attribute(JavadocReader.class.getName(), javadocReader)
.attribute(ConstraintReader.class.getName(), constraintReader)
.build());

assertThat(this.generatedSnippets.snippet(AUTO_RESPONSE_FIELDS)).is(
tableWithHeader("Path", "Type", "Optional", "Description")
.row("field1", "String", "true", "A string.")
.row("field2", "Decimal", "true", "A decimal."));
}


private void mockConstraintMessage(Class<?> type, String fieldName, String comment) {
when(constraintReader.getConstraintMessages(type, fieldName))
Expand Down Expand Up @@ -511,6 +530,10 @@ public static abstract class GenericTestResource<E> implements IGenericTestResou
public List<E> getItemsGeneric() {
return Collections.singletonList(createGeneric());
}

public E getItemGeneric() {
return createGeneric();
}
}

// actual method responses do not matter, they are here just for the illustration
Expand Down