summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--backend/src/main/java/org/luxons/sevenwonders/doc/builders/JSONDocApiObjectDocBuilder.java57
-rw-r--r--backend/src/main/java/org/luxons/sevenwonders/doc/builders/JSONDocApiObjectFieldDocBuilder.java42
-rw-r--r--backend/src/main/java/org/luxons/sevenwonders/doc/builders/JSONDocTemplateBuilder.java18
-rw-r--r--backend/src/main/java/org/luxons/sevenwonders/doc/builders/JSONDocTypeBuilder.java120
-rw-r--r--backend/src/main/java/org/luxons/sevenwonders/doc/builders/SpringObjectBuilder.java52
-rw-r--r--backend/src/main/java/org/luxons/sevenwonders/doc/builders/SpringResponseBuilder.java31
-rw-r--r--backend/src/main/java/org/luxons/sevenwonders/doc/scanner/JsonDocWebSocketScanner.java107
-rw-r--r--backend/src/main/java/org/luxons/sevenwonders/doc/scanner/ObjectsScanner.java209
8 files changed, 538 insertions, 98 deletions
diff --git a/backend/src/main/java/org/luxons/sevenwonders/doc/builders/JSONDocApiObjectDocBuilder.java b/backend/src/main/java/org/luxons/sevenwonders/doc/builders/JSONDocApiObjectDocBuilder.java
new file mode 100644
index 00000000..8a59451f
--- /dev/null
+++ b/backend/src/main/java/org/luxons/sevenwonders/doc/builders/JSONDocApiObjectDocBuilder.java
@@ -0,0 +1,57 @@
+package org.luxons.sevenwonders.doc.builders;
+
+import java.lang.reflect.Field;
+import java.util.Set;
+import java.util.TreeSet;
+
+import org.jsondoc.core.annotation.ApiObject;
+import org.jsondoc.core.annotation.ApiObjectField;
+import org.jsondoc.core.pojo.ApiObjectDoc;
+import org.jsondoc.core.pojo.ApiObjectFieldDoc;
+import org.jsondoc.core.scanner.DefaultJSONDocScanner;
+import org.jsondoc.core.scanner.builder.JSONDocApiVersionDocBuilder;
+
+public class JSONDocApiObjectDocBuilder {
+
+ public static ApiObjectDoc build(Class<?> clazz) {
+ ApiObject apiObject = clazz.getAnnotation(ApiObject.class);
+ ApiObjectDoc apiObjectDoc = new ApiObjectDoc();
+
+ Set<ApiObjectFieldDoc> fieldDocs = new TreeSet<ApiObjectFieldDoc>();
+ for (Field field : clazz.getDeclaredFields()) {
+ if (field.getAnnotation(ApiObjectField.class) != null) {
+ ApiObjectFieldDoc fieldDoc =
+ JSONDocApiObjectFieldDocBuilder.build(field.getAnnotation(ApiObjectField.class), field);
+ fieldDoc.setSupportedversions(JSONDocApiVersionDocBuilder.build(field));
+ fieldDocs.add(fieldDoc);
+ }
+ }
+
+ Class<?> c = clazz.getSuperclass();
+ if (c != null) {
+ if (c.isAnnotationPresent(ApiObject.class)) {
+ ApiObjectDoc objDoc = build(c);
+ fieldDocs.addAll(objDoc.getFields());
+ }
+ }
+
+ if (clazz.isEnum()) {
+ apiObjectDoc.setAllowedvalues(DefaultJSONDocScanner.enumConstantsToStringArray(clazz.getEnumConstants()));
+ }
+
+ if (apiObject.name().trim().isEmpty()) {
+ apiObjectDoc.setName(clazz.getSimpleName());
+ } else {
+ apiObjectDoc.setName(apiObject.name());
+ }
+
+ apiObjectDoc.setDescription(apiObject.description());
+ apiObjectDoc.setFields(fieldDocs);
+ apiObjectDoc.setGroup(apiObject.group());
+ apiObjectDoc.setVisibility(apiObject.visibility());
+ apiObjectDoc.setStage(apiObject.stage());
+ apiObjectDoc.setShow(apiObject.show());
+
+ return apiObjectDoc;
+ }
+}
diff --git a/backend/src/main/java/org/luxons/sevenwonders/doc/builders/JSONDocApiObjectFieldDocBuilder.java b/backend/src/main/java/org/luxons/sevenwonders/doc/builders/JSONDocApiObjectFieldDocBuilder.java
new file mode 100644
index 00000000..a1c9d7c6
--- /dev/null
+++ b/backend/src/main/java/org/luxons/sevenwonders/doc/builders/JSONDocApiObjectFieldDocBuilder.java
@@ -0,0 +1,42 @@
+package org.luxons.sevenwonders.doc.builders;
+
+import java.lang.reflect.Field;
+
+import org.jsondoc.core.annotation.ApiObjectField;
+import org.jsondoc.core.pojo.ApiObjectFieldDoc;
+import org.jsondoc.core.scanner.DefaultJSONDocScanner;
+import org.jsondoc.core.util.JSONDocHibernateValidatorProcessor;
+import org.jsondoc.core.util.JSONDocType;
+
+public class JSONDocApiObjectFieldDocBuilder {
+
+ public static ApiObjectFieldDoc build(ApiObjectField annotation, Field field) {
+ ApiObjectFieldDoc apiPojoFieldDoc = new ApiObjectFieldDoc();
+ if (!annotation.name().trim().isEmpty()) {
+ apiPojoFieldDoc.setName(annotation.name());
+ } else {
+ apiPojoFieldDoc.setName(field.getName());
+ }
+ apiPojoFieldDoc.setDescription(annotation.description());
+ apiPojoFieldDoc.setJsondocType(
+ JSONDocTypeBuilder.build(new JSONDocType(), field.getType(), field.getGenericType()));
+ // if allowedvalues property is populated on an enum field, then the enum values are overridden with the
+ // allowedvalues ones
+ if (field.getType().isEnum() && annotation.allowedvalues().length == 0) {
+ apiPojoFieldDoc.setAllowedvalues(
+ DefaultJSONDocScanner.enumConstantsToStringArray(field.getType().getEnumConstants()));
+ } else {
+ apiPojoFieldDoc.setAllowedvalues(annotation.allowedvalues());
+ }
+ apiPojoFieldDoc.setRequired(String.valueOf(annotation.required()));
+ apiPojoFieldDoc.setOrder(annotation.order());
+
+ if (!annotation.format().isEmpty()) {
+ apiPojoFieldDoc.addFormat(annotation.format());
+ }
+
+ JSONDocHibernateValidatorProcessor.processHibernateValidatorAnnotations(field, apiPojoFieldDoc);
+
+ return apiPojoFieldDoc;
+ }
+}
diff --git a/backend/src/main/java/org/luxons/sevenwonders/doc/builders/JSONDocTemplateBuilder.java b/backend/src/main/java/org/luxons/sevenwonders/doc/builders/JSONDocTemplateBuilder.java
index 78c86584..f518f319 100644
--- a/backend/src/main/java/org/luxons/sevenwonders/doc/builders/JSONDocTemplateBuilder.java
+++ b/backend/src/main/java/org/luxons/sevenwonders/doc/builders/JSONDocTemplateBuilder.java
@@ -21,6 +21,7 @@ import org.slf4j.LoggerFactory;
public class JSONDocTemplateBuilder {
private static final Logger log = LoggerFactory.getLogger(org.jsondoc.core.util.JSONDocTemplateBuilder.class);
+
private static final Map<Class<?>, Class<?>> primitives = new HashMap<Class<?>, Class<?>>();
static {
@@ -38,7 +39,7 @@ public class JSONDocTemplateBuilder {
public static JSONDocTemplate build(Class<?> clazz, Set<Class<?>> jsondocObjects) {
final JSONDocTemplate jsonDocTemplate = new JSONDocTemplate();
- if(jsondocObjects.contains(clazz)) {
+ if (jsondocObjects.contains(clazz)) {
try {
Set<JSONDocFieldWrapper> fields = getAllDeclaredFields(clazz);
@@ -53,7 +54,8 @@ public class JSONDocTemplateBuilder {
Object value;
// This condition is to avoid StackOverflow in case class "A"
// contains a field of type "A"
- if (field.getType().equals(clazz) || (apiObjectField != null && !apiObjectField.processtemplate())) {
+ if (field.getType().equals(clazz) || (apiObjectField != null
+ && !apiObjectField.processtemplate())) {
value = getValue(Object.class, field.getGenericType(), fieldName, jsondocObjects);
} else {
value = getValue(field.getType(), field.getGenericType(), fieldName, jsondocObjects);
@@ -61,7 +63,6 @@ public class JSONDocTemplateBuilder {
jsonDocTemplate.put(fieldName, value);
}
-
} catch (Exception e) {
log.error("Error in JSONDocTemplate creation for class [" + clazz.getCanonicalName() + "]", e);
}
@@ -70,30 +71,24 @@ public class JSONDocTemplateBuilder {
return jsonDocTemplate;
}
- private static Object getValue(Class<?> fieldClass, Type fieldGenericType, String fieldName, Set<Class<?>> jsondocObjects) {
+ private static Object getValue(Class<?> fieldClass, Type fieldGenericType, String fieldName,
+ Set<Class<?>> jsondocObjects) {
if (fieldClass.isPrimitive()) {
return getValue(wrap(fieldClass), null, fieldName, jsondocObjects);
-
} else if (Map.class.isAssignableFrom(fieldClass)) {
return new HashMap<Object, Object>();
-
} else if (Number.class.isAssignableFrom(fieldClass)) {
return new Integer(0);
-
} else if (String.class.isAssignableFrom(fieldClass) || fieldClass.isEnum()) {
return new String("");
-
} else if (Boolean.class.isAssignableFrom(fieldClass)) {
return new Boolean("true");
-
} else if (fieldClass.isArray() || Collection.class.isAssignableFrom(fieldClass)) {
return new ArrayList<Object>();
-
} else {
return build(fieldClass, jsondocObjects);
}
-
}
private static Set<JSONDocFieldWrapper> getAllDeclaredFields(Class<?> clazz) {
@@ -133,5 +128,4 @@ public class JSONDocTemplateBuilder {
private static <T> Class<T> wrap(Class<T> clazz) {
return clazz.isPrimitive() ? (Class<T>) primitives.get(clazz) : clazz;
}
-
}
diff --git a/backend/src/main/java/org/luxons/sevenwonders/doc/builders/JSONDocTypeBuilder.java b/backend/src/main/java/org/luxons/sevenwonders/doc/builders/JSONDocTypeBuilder.java
new file mode 100644
index 00000000..4584e7cf
--- /dev/null
+++ b/backend/src/main/java/org/luxons/sevenwonders/doc/builders/JSONDocTypeBuilder.java
@@ -0,0 +1,120 @@
+package org.luxons.sevenwonders.doc.builders;
+
+import java.lang.reflect.GenericArrayType;
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
+import java.lang.reflect.TypeVariable;
+import java.lang.reflect.WildcardType;
+import java.util.Collection;
+import java.util.Map;
+
+import org.jsondoc.core.annotation.ApiObject;
+import org.jsondoc.core.util.JSONDocDefaultType;
+import org.jsondoc.core.util.JSONDocType;
+
+public class JSONDocTypeBuilder {
+
+ private static final String WILDCARD = "wildcard";
+
+ private static final String UNDEFINED = "undefined";
+
+ private static final String ARRAY = "array";
+
+ public static JSONDocType build(JSONDocType jsondocType, Class<?> clazz, Type type) {
+ if (clazz.isAssignableFrom(JSONDocDefaultType.class)) {
+ jsondocType.addItemToType(UNDEFINED);
+ return jsondocType;
+ }
+
+ if (Map.class.isAssignableFrom(clazz)) {
+ jsondocType.addItemToType(getCustomClassName(clazz));
+
+ if (type instanceof ParameterizedType) {
+ Type mapKeyType = ((ParameterizedType) type).getActualTypeArguments()[0];
+ Type mapValueType = ((ParameterizedType) type).getActualTypeArguments()[1];
+
+ jsondocType.setMapKey(new JSONDocType());
+ jsondocType.setMapValue(new JSONDocType());
+
+ if (mapKeyType instanceof Class) {
+ jsondocType.setMapKey(new JSONDocType(((Class<?>) mapKeyType).getSimpleName()));
+ } else if (mapKeyType instanceof WildcardType) {
+ jsondocType.setMapKey(new JSONDocType(WILDCARD));
+ } else if (mapKeyType instanceof TypeVariable<?>) {
+ jsondocType.setMapKey(new JSONDocType(((TypeVariable<?>) mapKeyType).getName()));
+ } else {
+ jsondocType.setMapKey(
+ build(jsondocType.getMapKey(), (Class<?>) ((ParameterizedType) mapKeyType).getRawType(),
+ mapKeyType));
+ }
+
+ if (mapValueType instanceof Class) {
+ jsondocType.setMapValue(new JSONDocType(((Class<?>) mapValueType).getSimpleName()));
+ } else if (mapValueType instanceof WildcardType) {
+ jsondocType.setMapValue(new JSONDocType(WILDCARD));
+ } else if (mapValueType instanceof TypeVariable<?>) {
+ jsondocType.setMapValue(new JSONDocType(((TypeVariable<?>) mapValueType).getName()));
+ } else {
+ jsondocType.setMapValue(
+ build(jsondocType.getMapValue(), (Class<?>) ((ParameterizedType) mapValueType).getRawType(),
+ mapValueType));
+ }
+ }
+ } else if (Collection.class.isAssignableFrom(clazz)) {
+ if (type instanceof ParameterizedType) {
+ Type parametrizedType = ((ParameterizedType) type).getActualTypeArguments()[0];
+ jsondocType.addItemToType(getCustomClassName(clazz));
+
+ if (parametrizedType instanceof Class) {
+ jsondocType.addItemToType(getCustomClassName((Class<?>) parametrizedType));
+ } else if (parametrizedType instanceof WildcardType) {
+ jsondocType.addItemToType(WILDCARD);
+ } else if (parametrizedType instanceof TypeVariable<?>) {
+ jsondocType.addItemToType(((TypeVariable<?>) parametrizedType).getName());
+ } else {
+ return build(jsondocType, (Class<?>) ((ParameterizedType) parametrizedType).getRawType(),
+ parametrizedType);
+ }
+ } else if (type instanceof GenericArrayType) {
+ return build(jsondocType, clazz, ((GenericArrayType) type).getGenericComponentType());
+ } else {
+ jsondocType.addItemToType(getCustomClassName(clazz));
+ }
+ } else if (clazz.isArray()) {
+ jsondocType.addItemToType(ARRAY);
+ Class<?> componentType = clazz.getComponentType();
+ return build(jsondocType, componentType, type);
+ } else {
+ jsondocType.addItemToType(getCustomClassName(clazz));
+ if (type instanceof ParameterizedType) {
+ Type parametrizedType = ((ParameterizedType) type).getActualTypeArguments()[0];
+
+ if (parametrizedType instanceof Class) {
+ jsondocType.addItemToType(getCustomClassName((Class<?>) parametrizedType));
+ } else if (parametrizedType instanceof WildcardType) {
+ jsondocType.addItemToType(WILDCARD);
+ } else if (parametrizedType instanceof TypeVariable<?>) {
+ jsondocType.addItemToType(((TypeVariable<?>) parametrizedType).getName());
+ } else {
+ return build(jsondocType, (Class<?>) ((ParameterizedType) parametrizedType).getRawType(),
+ parametrizedType);
+ }
+ }
+ }
+
+ return jsondocType;
+ }
+
+ private static String getCustomClassName(Class<?> clazz) {
+ if (clazz.isAnnotationPresent(ApiObject.class)) {
+ ApiObject annotation = clazz.getAnnotation(ApiObject.class);
+ if (annotation.name().isEmpty()) {
+ return clazz.getSimpleName().toLowerCase();
+ } else {
+ return annotation.name();
+ }
+ } else {
+ return clazz.getSimpleName();
+ }
+ }
+}
diff --git a/backend/src/main/java/org/luxons/sevenwonders/doc/builders/SpringObjectBuilder.java b/backend/src/main/java/org/luxons/sevenwonders/doc/builders/SpringObjectBuilder.java
new file mode 100644
index 00000000..46f38e8b
--- /dev/null
+++ b/backend/src/main/java/org/luxons/sevenwonders/doc/builders/SpringObjectBuilder.java
@@ -0,0 +1,52 @@
+package org.luxons.sevenwonders.doc.builders;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
+import java.util.Set;
+import java.util.TreeSet;
+
+import org.jsondoc.core.pojo.ApiObjectDoc;
+import org.jsondoc.core.pojo.ApiObjectFieldDoc;
+import org.jsondoc.core.scanner.DefaultJSONDocScanner;
+import org.jsondoc.core.util.JSONDocHibernateValidatorProcessor;
+import org.jsondoc.core.util.JSONDocType;
+
+public class SpringObjectBuilder {
+
+ public static ApiObjectDoc buildObject(Class<?> clazz) {
+ ApiObjectDoc apiObjectDoc = new ApiObjectDoc();
+ apiObjectDoc.setName(clazz.getSimpleName());
+
+ Set<ApiObjectFieldDoc> fieldDocs = new TreeSet<ApiObjectFieldDoc>();
+
+ for (Field field : clazz.getDeclaredFields()) {
+ ApiObjectFieldDoc fieldDoc = new ApiObjectFieldDoc();
+ fieldDoc.setName(field.getName());
+ fieldDoc.setOrder(Integer.MAX_VALUE);
+ fieldDoc.setRequired(DefaultJSONDocScanner.UNDEFINED.toUpperCase());
+ fieldDoc.setJsondocType(
+ JSONDocTypeBuilder.build(new JSONDocType(), field.getType(), field.getGenericType()));
+
+ JSONDocHibernateValidatorProcessor.processHibernateValidatorAnnotations(field, fieldDoc);
+
+ fieldDocs.add(fieldDoc);
+ }
+
+ Class<?> superclass = clazz.getSuperclass();
+ if (superclass != null) {
+ ApiObjectDoc parentObjectDoc = buildObject(superclass);
+ fieldDocs.addAll(parentObjectDoc.getFields());
+ }
+
+ if (clazz.isEnum()) {
+ apiObjectDoc.setAllowedvalues(DefaultJSONDocScanner.enumConstantsToStringArray(clazz.getEnumConstants()));
+ }
+
+ apiObjectDoc.setFields(fieldDocs);
+ if (Modifier.isAbstract(clazz.getModifiers())) {
+ apiObjectDoc.setShow(false);
+ }
+
+ return apiObjectDoc;
+ }
+}
diff --git a/backend/src/main/java/org/luxons/sevenwonders/doc/builders/SpringResponseBuilder.java b/backend/src/main/java/org/luxons/sevenwonders/doc/builders/SpringResponseBuilder.java
new file mode 100644
index 00000000..4d8c0ed9
--- /dev/null
+++ b/backend/src/main/java/org/luxons/sevenwonders/doc/builders/SpringResponseBuilder.java
@@ -0,0 +1,31 @@
+package org.luxons.sevenwonders.doc.builders;
+
+import java.lang.reflect.Method;
+
+import org.jsondoc.core.pojo.ApiResponseObjectDoc;
+import org.jsondoc.core.util.JSONDocType;
+import org.springframework.http.ResponseEntity;
+
+public class SpringResponseBuilder {
+
+ /**
+ * Builds the ApiResponseObjectDoc from the method's return type and checks if the first type corresponds to a
+ * ResponseEntity class. In that case removes the "responseentity" string from the final list because it's not
+ * important to the documentation user.
+ *
+ * @param method
+ * the method to create the response object for
+ *
+ * @return the created {@link ApiResponseObjectDoc}
+ */
+ public static ApiResponseObjectDoc buildResponse(Method method) {
+ ApiResponseObjectDoc apiResponseObjectDoc = new ApiResponseObjectDoc(
+ JSONDocTypeBuilder.build(new JSONDocType(), method.getReturnType(), method.getGenericReturnType()));
+
+ if (method.getReturnType().isAssignableFrom(ResponseEntity.class)) {
+ apiResponseObjectDoc.getJsondocType().getType().remove(0);
+ }
+
+ return apiResponseObjectDoc;
+ }
+}
diff --git a/backend/src/main/java/org/luxons/sevenwonders/doc/scanner/JsonDocWebSocketScanner.java b/backend/src/main/java/org/luxons/sevenwonders/doc/scanner/JsonDocWebSocketScanner.java
index 0f5f5557..d7523577 100644
--- a/backend/src/main/java/org/luxons/sevenwonders/doc/scanner/JsonDocWebSocketScanner.java
+++ b/backend/src/main/java/org/luxons/sevenwonders/doc/scanner/JsonDocWebSocketScanner.java
@@ -1,21 +1,18 @@
package org.luxons.sevenwonders.doc.scanner;
-import java.lang.reflect.Field;
import java.lang.reflect.Method;
-import java.lang.reflect.Modifier;
-import java.lang.reflect.Type;
import java.net.URL;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
-import java.util.stream.Collectors;
-import com.google.common.collect.Sets;
import org.jsondoc.core.annotation.Api;
import org.jsondoc.core.annotation.ApiMethod;
+import org.jsondoc.core.annotation.ApiObject;
import org.jsondoc.core.pojo.ApiMethodDoc;
+import org.jsondoc.core.pojo.ApiObjectDoc;
import org.jsondoc.core.pojo.JSONDoc;
import org.jsondoc.core.pojo.JSONDoc.MethodDisplay;
import org.jsondoc.core.pojo.JSONDocTemplate;
@@ -27,12 +24,14 @@ import org.jsondoc.springmvc.scanner.builder.SpringHeaderBuilder;
import org.jsondoc.springmvc.scanner.builder.SpringPathVariableBuilder;
import org.jsondoc.springmvc.scanner.builder.SpringProducesBuilder;
import org.jsondoc.springmvc.scanner.builder.SpringQueryParamBuilder;
-import org.jsondoc.springmvc.scanner.builder.SpringResponseBuilder;
import org.jsondoc.springmvc.scanner.builder.SpringResponseStatusBuilder;
import org.jsondoc.springmvc.scanner.builder.SpringVerbBuilder;
+import org.luxons.sevenwonders.doc.builders.JSONDocApiObjectDocBuilder;
import org.luxons.sevenwonders.doc.builders.JSONDocTemplateBuilder;
+import org.luxons.sevenwonders.doc.builders.SpringObjectBuilder;
import org.luxons.sevenwonders.doc.builders.SpringPathBuilder;
import org.luxons.sevenwonders.doc.builders.SpringRequestBodyBuilder;
+import org.luxons.sevenwonders.doc.builders.SpringResponseBuilder;
import org.reflections.Reflections;
import org.reflections.scanners.MethodAnnotationsScanner;
import org.reflections.util.ClasspathHelper;
@@ -46,11 +45,9 @@ import org.springframework.web.bind.annotation.RequestMapping;
public class JsonDocWebSocketScanner extends Spring4JSONDocScanner {
- /**
- * Returns the main <code>ApiDoc</code>, containing <code>ApiMethodDoc</code> and <code>ApiObjectDoc</code> objects
- * @return An <code>ApiDoc</code> object
- */
- public JSONDoc getJSONDoc(String version, String basePath, List<String> packages, boolean playgroundEnabled, MethodDisplay displayMethodAs) {
+ @Override
+ public JSONDoc getJSONDoc(String version, String basePath, List<String> packages, boolean playgroundEnabled,
+ MethodDisplay displayMethodAs) {
Set<URL> urls = new HashSet<URL>();
FilterBuilder filter = new FilterBuilder();
@@ -61,7 +58,9 @@ public class JsonDocWebSocketScanner extends Spring4JSONDocScanner {
filter.includePackage(pkg);
}
- reflections = new Reflections(new ConfigurationBuilder().filterInputsBy(filter).setUrls(urls).addScanners(new MethodAnnotationsScanner()));
+ reflections = new Reflections(new ConfigurationBuilder().filterInputsBy(filter)
+ .setUrls(urls)
+ .addScanners(new MethodAnnotationsScanner()));
JSONDoc jsondocDoc = new JSONDoc(version, basePath);
jsondocDoc.setPlaygroundEnabled(playgroundEnabled);
@@ -138,84 +137,20 @@ public class JsonDocWebSocketScanner extends Spring4JSONDocScanner {
@Override
public Set<Class<?>> jsondocObjects(List<String> packages) {
- Set<Class<?>> candidates = getRootApiObjects();
- Set<Class<?>> subCandidates = Sets.newHashSet();
-
- // This is to get objects' fields that are not returned nor part of the body request of a method, but that
- // are a field of an object returned or a body of a request of a method
- for (Class<?> clazz : candidates) {
- appendSubCandidates(clazz, subCandidates);
- }
- candidates.addAll(subCandidates);
-
- return candidates.stream().filter(clazz -> inWhiteListedPackages(packages, clazz)).collect(Collectors.toSet());
- }
-
- private Set<Class<?>> getRootApiObjects() {
- Set<Class<?>> candidates = Sets.newHashSet();
- Set<Method> methodsToDocument = getMethodsToDocument();
- for (Method method : methodsToDocument) {
- addReturnType(candidates, method);
- addBodyParam(candidates, method);
- }
- return candidates;
- }
-
- private void addReturnType(Set<Class<?>> candidates, Method method) {
- Class<?> returnValueClass = method.getReturnType();
- if (returnValueClass.isPrimitive() || returnValueClass.equals(JSONDoc.class)) {
- return;
- }
- buildJSONDocObjectsCandidates(candidates, returnValueClass, method.getGenericReturnType(),
- reflections);
- }
-
- private void addBodyParam(Set<Class<?>> candidates, Method method) {
- int bodyParamIndex = SpringRequestBodyBuilder.getIndexOfBodyParam(method);
- if (bodyParamIndex >= 0) {
- Class<?> bodyParamClass = method.getParameterTypes()[bodyParamIndex];
- Type bodyParamType = method.getGenericParameterTypes()[bodyParamIndex];
- buildJSONDocObjectsCandidates(candidates, bodyParamClass, bodyParamType, reflections);
- }
+ return new ObjectsScanner(reflections).findJsondocObjects(packages);
}
- private Set<Method> getMethodsToDocument() {
- Set<Method> methodsAnnotatedWith = reflections.getMethodsAnnotatedWith(RequestMapping.class);
- methodsAnnotatedWith.addAll(reflections.getMethodsAnnotatedWith(SubscribeMapping.class));
- methodsAnnotatedWith.addAll(reflections.getMethodsAnnotatedWith(MessageMapping.class));
- return methodsAnnotatedWith;
- }
-
- private boolean inWhiteListedPackages(List<String> packages, Class<?> clazz) {
- Package p = clazz.getPackage();
- return p != null && packages.stream().anyMatch(whiteListedPkg -> p.getName().startsWith(whiteListedPkg));
+ @Override
+ public ApiObjectDoc initApiObjectDoc(Class<?> clazz) {
+ return SpringObjectBuilder.buildObject(clazz);
}
- private void appendSubCandidates(Class<?> clazz, Set<Class<?>> subCandidates) {
- if (clazz.isPrimitive() || clazz.equals(Class.class)) {
- return;
- }
-
- for (Field field : clazz.getDeclaredFields()) {
- if (!isValidForRecursion(field)) {
- continue;
- }
-
- Class<?> fieldClass = field.getType();
- Set<Class<?>> fieldCandidates = new HashSet<>();
- buildJSONDocObjectsCandidates(fieldCandidates, fieldClass, field.getGenericType(), reflections);
-
- for (Class<?> candidate : fieldCandidates) {
- if (!subCandidates.contains(candidate)) {
- subCandidates.add(candidate);
-
- appendSubCandidates(candidate, subCandidates);
- }
- }
+ @Override
+ public ApiObjectDoc mergeApiObjectDoc(Class<?> clazz, ApiObjectDoc apiObjectDoc) {
+ if (clazz.isAnnotationPresent(ApiObject.class)) {
+ ApiObjectDoc jsondocApiObjectDoc = JSONDocApiObjectDocBuilder.build(clazz);
+ BeanUtils.copyProperties(jsondocApiObjectDoc, apiObjectDoc);
}
- }
-
- private static boolean isValidForRecursion(Field field) {
- return !field.isSynthetic() && !field.getType().isPrimitive() && !Modifier.isTransient(field.getModifiers());
+ return apiObjectDoc;
}
}
diff --git a/backend/src/main/java/org/luxons/sevenwonders/doc/scanner/ObjectsScanner.java b/backend/src/main/java/org/luxons/sevenwonders/doc/scanner/ObjectsScanner.java
new file mode 100644
index 00000000..e20406ef
--- /dev/null
+++ b/backend/src/main/java/org/luxons/sevenwonders/doc/scanner/ObjectsScanner.java
@@ -0,0 +1,209 @@
+package org.luxons.sevenwonders.doc.scanner;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.GenericArrayType;
+import java.lang.reflect.Method;
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
+import java.lang.reflect.TypeVariable;
+import java.lang.reflect.WildcardType;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+import com.google.common.collect.Sets;
+import org.jsondoc.core.pojo.JSONDoc;
+import org.luxons.sevenwonders.doc.builders.SpringRequestBodyBuilder;
+import org.reflections.Reflections;
+import org.springframework.messaging.handler.annotation.MessageMapping;
+import org.springframework.messaging.simp.annotation.SubscribeMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+
+public class ObjectsScanner {
+
+ private final Reflections reflections;
+
+ public ObjectsScanner(Reflections reflections) {
+ this.reflections = reflections;
+ }
+
+ public Set<Class<?>> findJsondocObjects(List<String> packages) {
+ Set<Class<?>> candidates = getRootApiObjects();
+ Set<Class<?>> subCandidates = Sets.newHashSet();
+
+ // This is to get objects' fields that are not returned nor part of the body request of a method, but that
+ // are a field of an object returned or a body of a request of a method
+ for (Class<?> clazz : candidates) {
+ appendSubCandidates(clazz, subCandidates);
+ }
+ candidates.addAll(subCandidates);
+
+ return candidates.stream().filter(clazz -> inWhiteListedPackages(packages, clazz)).collect(Collectors.toSet());
+ }
+
+ private Set<Class<?>> getRootApiObjects() {
+ Set<Class<?>> candidates = Sets.newHashSet();
+ Set<Method> methodsToDocument = getMethodsToDocument();
+ for (Method method : methodsToDocument) {
+ addReturnType(candidates, method);
+ addBodyParam(candidates, method);
+ }
+ return candidates;
+ }
+
+ private void addReturnType(Set<Class<?>> candidates, Method method) {
+ Class<?> returnValueClass = method.getReturnType();
+ if (returnValueClass.isPrimitive() || returnValueClass.equals(JSONDoc.class)) {
+ return;
+ }
+ buildJSONDocObjectsCandidates(candidates, returnValueClass, method.getGenericReturnType(), reflections);
+ }
+
+ private void addBodyParam(Set<Class<?>> candidates, Method method) {
+ int bodyParamIndex = SpringRequestBodyBuilder.getIndexOfBodyParam(method);
+ if (bodyParamIndex >= 0) {
+ Class<?> bodyParamClass = method.getParameterTypes()[bodyParamIndex];
+ Type bodyParamType = method.getGenericParameterTypes()[bodyParamIndex];
+ buildJSONDocObjectsCandidates(candidates, bodyParamClass, bodyParamType, reflections);
+ }
+ }
+
+ private Set<Method> getMethodsToDocument() {
+ Set<Method> methodsAnnotatedWith = reflections.getMethodsAnnotatedWith(RequestMapping.class);
+ methodsAnnotatedWith.addAll(reflections.getMethodsAnnotatedWith(SubscribeMapping.class));
+ methodsAnnotatedWith.addAll(reflections.getMethodsAnnotatedWith(MessageMapping.class));
+ return methodsAnnotatedWith;
+ }
+
+ private boolean inWhiteListedPackages(List<String> packages, Class<?> clazz) {
+ Package p = clazz.getPackage();
+ return p != null && packages.stream().anyMatch(whiteListedPkg -> p.getName().startsWith(whiteListedPkg));
+ }
+
+ private void appendSubCandidates(Class<?> clazz, Set<Class<?>> subCandidates) {
+ if (clazz.isPrimitive() || clazz.equals(Class.class)) {
+ return;
+ }
+
+ for (Field field : clazz.getDeclaredFields()) {
+ if (!isValidForRecursion(field)) {
+ continue;
+ }
+
+ Class<?> fieldClass = field.getType();
+ Set<Class<?>> fieldCandidates = new HashSet<>();
+ buildJSONDocObjectsCandidates(fieldCandidates, fieldClass, field.getGenericType(), reflections);
+
+ for (Class<?> candidate : fieldCandidates) {
+ if (!subCandidates.contains(candidate)) {
+ subCandidates.add(candidate);
+
+ appendSubCandidates(candidate, subCandidates);
+ }
+ }
+ }
+ }
+
+ private static boolean isValidForRecursion(Field field) {
+ // return !field.isSynthetic() && !field.getType().isPrimitive() && !Modifier.isTransient(field
+ // .getModifiers());
+ return true;
+ }
+
+ public static Set<Class<?>> buildJSONDocObjectsCandidates(Set<Class<?>> candidates, Class<?> clazz, Type type,
+ Reflections reflections) {
+
+ if (Map.class.isAssignableFrom(clazz)) {
+
+ if (type instanceof ParameterizedType) {
+ Type mapKeyType = ((ParameterizedType) type).getActualTypeArguments()[0];
+ Type mapValueType = ((ParameterizedType) type).getActualTypeArguments()[1];
+
+ if (mapKeyType instanceof Class) {
+ candidates.add((Class<?>) mapKeyType);
+ } else if (mapKeyType instanceof WildcardType) {
+ candidates.add(Void.class);
+ } else {
+ if (mapKeyType instanceof ParameterizedType) {
+ candidates.addAll(buildJSONDocObjectsCandidates(candidates,
+ (Class<?>) ((ParameterizedType) mapKeyType).getRawType(), mapKeyType, reflections));
+ }
+ }
+
+ if (mapValueType instanceof Class) {
+ candidates.add((Class<?>) mapValueType);
+ } else if (mapValueType instanceof WildcardType) {
+ candidates.add(Void.class);
+ } else {
+ if (mapValueType instanceof ParameterizedType) {
+ candidates.addAll(buildJSONDocObjectsCandidates(candidates,
+ (Class<?>) ((ParameterizedType) mapValueType).getRawType(), mapValueType, reflections));
+ }
+ }
+ }
+ } else if (Collection.class.isAssignableFrom(clazz)) {
+ if (type instanceof ParameterizedType) {
+ Type parametrizedType = ((ParameterizedType) type).getActualTypeArguments()[0];
+ candidates.add(clazz);
+
+ if (parametrizedType instanceof Class) {
+ candidates.add((Class<?>) parametrizedType);
+ } else if (parametrizedType instanceof WildcardType) {
+ candidates.add(Void.class);
+ } else {
+ candidates.addAll(buildJSONDocObjectsCandidates(candidates,
+ (Class<?>) ((ParameterizedType) parametrizedType).getRawType(), parametrizedType,
+ reflections));
+ }
+ } else if (type instanceof GenericArrayType) {
+ candidates.addAll(buildJSONDocObjectsCandidates(candidates, clazz,
+ ((GenericArrayType) type).getGenericComponentType(), reflections));
+ } else {
+ candidates.add(clazz);
+ }
+ } else if (clazz.isArray()) {
+ Class<?> componentType = clazz.getComponentType();
+ candidates.addAll(buildJSONDocObjectsCandidates(candidates, componentType, type, reflections));
+ } else {
+ if (type instanceof ParameterizedType) {
+ Type parametrizedType = ((ParameterizedType) type).getActualTypeArguments()[0];
+
+ if (parametrizedType instanceof Class) {
+ Class<?> candidate = (Class<?>) parametrizedType;
+ if (candidate.isInterface()) {
+ for (Class<?> implementation : reflections.getSubTypesOf(candidate)) {
+ buildJSONDocObjectsCandidates(candidates, implementation, parametrizedType, reflections);
+ }
+ } else {
+ candidates.add(candidate);
+ candidates.addAll(buildJSONDocObjectsCandidates(candidates,
+ (Class<?>) ((ParameterizedType) type).getRawType(), parametrizedType, reflections));
+ }
+ } else if (parametrizedType instanceof WildcardType) {
+ candidates.add(Void.class);
+ candidates.addAll(buildJSONDocObjectsCandidates(candidates,
+ (Class<?>) ((ParameterizedType) type).getRawType(), parametrizedType, reflections));
+ } else if (parametrizedType instanceof TypeVariable<?>) {
+ candidates.add(Void.class);
+ candidates.addAll(buildJSONDocObjectsCandidates(candidates,
+ (Class<?>) ((ParameterizedType) type).getRawType(), parametrizedType, reflections));
+ } else {
+ candidates.addAll(buildJSONDocObjectsCandidates(candidates,
+ (Class<?>) ((ParameterizedType) parametrizedType).getRawType(), parametrizedType,
+ reflections));
+ }
+ } else if (clazz.isInterface()) {
+ for (Class<?> implementation : reflections.getSubTypesOf(clazz)) {
+ candidates.addAll(buildJSONDocObjectsCandidates(candidates, implementation, type, reflections));
+ }
+ } else {
+ candidates.add(clazz);
+ }
+ }
+
+ return candidates;
+ }
+}
bgstack15