diff options
Diffstat (limited to 'backend')
24 files changed, 25 insertions, 1069 deletions
diff --git a/backend/build.gradle b/backend/build.gradle index 5193f0cb..6e728b12 100644 --- a/backend/build.gradle +++ b/backend/build.gradle @@ -18,8 +18,8 @@ repositories { dependencies { compile 'com.google.code.gson:gson:2.8.0' compile 'ch.qos.logback:logback-classic:1.1.8' - compile 'org.jsondoc:spring-boot-starter-jsondoc:1.2.17' - compile 'org.jsondoc:jsondoc-ui-webjar:1.2.17' + compile 'org.hildan.livedoc:livedoc-springboot:0.2.0' + compile 'org.hildan.livedoc:livedoc-ui-webjar:0.2.0' compile 'org.springframework.boot:spring-boot-starter-websocket' compile 'org.springframework.security:spring-security-core:4.2.0.RELEASE' diff --git a/backend/src/main/java/org/luxons/sevenwonders/SevenWonders.java b/backend/src/main/java/org/luxons/sevenwonders/SevenWonders.java index eba0c607..c656b2c3 100644 --- a/backend/src/main/java/org/luxons/sevenwonders/SevenWonders.java +++ b/backend/src/main/java/org/luxons/sevenwonders/SevenWonders.java @@ -1,6 +1,6 @@ package org.luxons.sevenwonders; -import org.jsondoc.spring.boot.starter.EnableJSONDoc; +import org.hildan.livedoc.spring.boot.starter.EnableJSONDoc; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; diff --git a/backend/src/main/java/org/luxons/sevenwonders/actions/ChooseNameAction.java b/backend/src/main/java/org/luxons/sevenwonders/actions/ChooseNameAction.java index be5e97ea..e6ecaa17 100644 --- a/backend/src/main/java/org/luxons/sevenwonders/actions/ChooseNameAction.java +++ b/backend/src/main/java/org/luxons/sevenwonders/actions/ChooseNameAction.java @@ -3,8 +3,8 @@ package org.luxons.sevenwonders.actions; import javax.validation.constraints.NotNull; import javax.validation.constraints.Size; -import org.jsondoc.core.annotation.ApiObject; -import org.jsondoc.core.annotation.ApiObjectField; +import org.hildan.livedoc.core.annotation.ApiObject; +import org.hildan.livedoc.core.annotation.ApiObjectField; @ApiObject(name = "Choose Name Action", description = "The action to choose the player's name. This is the first action that should be called.", diff --git a/backend/src/main/java/org/luxons/sevenwonders/actions/CreateGameAction.java b/backend/src/main/java/org/luxons/sevenwonders/actions/CreateGameAction.java index 4ad957b8..91984016 100644 --- a/backend/src/main/java/org/luxons/sevenwonders/actions/CreateGameAction.java +++ b/backend/src/main/java/org/luxons/sevenwonders/actions/CreateGameAction.java @@ -3,8 +3,8 @@ package org.luxons.sevenwonders.actions; import javax.validation.constraints.NotNull; import javax.validation.constraints.Size; -import org.jsondoc.core.annotation.ApiObject; -import org.jsondoc.core.annotation.ApiObjectField; +import org.hildan.livedoc.core.annotation.ApiObject; +import org.hildan.livedoc.core.annotation.ApiObjectField; @ApiObject(name = "Create Game Action", description = "The action to create a game.", diff --git a/backend/src/main/java/org/luxons/sevenwonders/actions/JoinGameAction.java b/backend/src/main/java/org/luxons/sevenwonders/actions/JoinGameAction.java index a392378c..eeb3381a 100644 --- a/backend/src/main/java/org/luxons/sevenwonders/actions/JoinGameAction.java +++ b/backend/src/main/java/org/luxons/sevenwonders/actions/JoinGameAction.java @@ -2,8 +2,8 @@ package org.luxons.sevenwonders.actions; import javax.validation.constraints.NotNull; -import org.jsondoc.core.annotation.ApiObject; -import org.jsondoc.core.annotation.ApiObjectField; +import org.hildan.livedoc.core.annotation.ApiObject; +import org.hildan.livedoc.core.annotation.ApiObjectField; @ApiObject(name = "Join Game Action", description = "The action to join a game.", diff --git a/backend/src/main/java/org/luxons/sevenwonders/actions/PrepareMoveAction.java b/backend/src/main/java/org/luxons/sevenwonders/actions/PrepareMoveAction.java index 02899eab..5fd32c4c 100644 --- a/backend/src/main/java/org/luxons/sevenwonders/actions/PrepareMoveAction.java +++ b/backend/src/main/java/org/luxons/sevenwonders/actions/PrepareMoveAction.java @@ -2,8 +2,8 @@ package org.luxons.sevenwonders.actions; import javax.validation.constraints.NotNull; -import org.jsondoc.core.annotation.ApiObject; -import org.jsondoc.core.annotation.ApiObjectField; +import org.hildan.livedoc.core.annotation.ApiObject; +import org.hildan.livedoc.core.annotation.ApiObjectField; import org.luxons.sevenwonders.game.api.PlayerMove; @ApiObject(name = "Prepare Move Action", diff --git a/backend/src/main/java/org/luxons/sevenwonders/actions/ReorderPlayersAction.java b/backend/src/main/java/org/luxons/sevenwonders/actions/ReorderPlayersAction.java index e457caf4..ba819fe0 100644 --- a/backend/src/main/java/org/luxons/sevenwonders/actions/ReorderPlayersAction.java +++ b/backend/src/main/java/org/luxons/sevenwonders/actions/ReorderPlayersAction.java @@ -4,8 +4,8 @@ import java.util.List; import javax.validation.constraints.NotNull; -import org.jsondoc.core.annotation.ApiObject; -import org.jsondoc.core.annotation.ApiObjectField; +import org.hildan.livedoc.core.annotation.ApiObject; +import org.hildan.livedoc.core.annotation.ApiObjectField; @ApiObject(name = "Reorder Players Action", description = "The action to update the order of the players around the table. Can only be called in the " diff --git a/backend/src/main/java/org/luxons/sevenwonders/actions/UpdateSettingsAction.java b/backend/src/main/java/org/luxons/sevenwonders/actions/UpdateSettingsAction.java index fa454995..410dd8ea 100644 --- a/backend/src/main/java/org/luxons/sevenwonders/actions/UpdateSettingsAction.java +++ b/backend/src/main/java/org/luxons/sevenwonders/actions/UpdateSettingsAction.java @@ -2,8 +2,8 @@ package org.luxons.sevenwonders.actions; import javax.validation.constraints.NotNull; -import org.jsondoc.core.annotation.ApiObject; -import org.jsondoc.core.annotation.ApiObjectField; +import org.hildan.livedoc.core.annotation.ApiObject; +import org.hildan.livedoc.core.annotation.ApiObjectField; import org.luxons.sevenwonders.game.api.CustomizableSettings; @ApiObject(name = "Update Settings Action", diff --git a/backend/src/main/java/org/luxons/sevenwonders/controllers/GameBrowserController.java b/backend/src/main/java/org/luxons/sevenwonders/controllers/GameBrowserController.java index b482407f..26250b8a 100644 --- a/backend/src/main/java/org/luxons/sevenwonders/controllers/GameBrowserController.java +++ b/backend/src/main/java/org/luxons/sevenwonders/controllers/GameBrowserController.java @@ -4,8 +4,8 @@ import java.security.Principal; import java.util.Collection; import java.util.Collections; -import org.jsondoc.core.annotation.Api; -import org.jsondoc.core.annotation.ApiMethod; +import org.hildan.livedoc.core.annotation.Api; +import org.hildan.livedoc.core.annotation.ApiMethod; import org.luxons.sevenwonders.actions.CreateGameAction; import org.luxons.sevenwonders.actions.JoinGameAction; import org.luxons.sevenwonders.errors.ApiMisuseException; diff --git a/backend/src/main/java/org/luxons/sevenwonders/controllers/GameController.java b/backend/src/main/java/org/luxons/sevenwonders/controllers/GameController.java index 513a7cdb..e33d2012 100644 --- a/backend/src/main/java/org/luxons/sevenwonders/controllers/GameController.java +++ b/backend/src/main/java/org/luxons/sevenwonders/controllers/GameController.java @@ -3,8 +3,8 @@ package org.luxons.sevenwonders.controllers; import java.security.Principal; import java.util.List; -import org.jsondoc.core.annotation.Api; -import org.jsondoc.core.annotation.ApiMethod; +import org.hildan.livedoc.core.annotation.Api; +import org.hildan.livedoc.core.annotation.ApiMethod; import org.luxons.sevenwonders.actions.PrepareMoveAction; import org.luxons.sevenwonders.game.Game; import org.luxons.sevenwonders.game.api.PlayerTurnInfo; diff --git a/backend/src/main/java/org/luxons/sevenwonders/controllers/HomeController.java b/backend/src/main/java/org/luxons/sevenwonders/controllers/HomeController.java index dd6cad7f..4e0c1083 100644 --- a/backend/src/main/java/org/luxons/sevenwonders/controllers/HomeController.java +++ b/backend/src/main/java/org/luxons/sevenwonders/controllers/HomeController.java @@ -2,8 +2,8 @@ package org.luxons.sevenwonders.controllers; import java.security.Principal; -import org.jsondoc.core.annotation.Api; -import org.jsondoc.core.annotation.ApiMethod; +import org.hildan.livedoc.core.annotation.Api; +import org.hildan.livedoc.core.annotation.ApiMethod; import org.luxons.sevenwonders.actions.ChooseNameAction; import org.luxons.sevenwonders.lobby.Player; import org.luxons.sevenwonders.repositories.PlayerRepository; diff --git a/backend/src/main/java/org/luxons/sevenwonders/controllers/LobbyController.java b/backend/src/main/java/org/luxons/sevenwonders/controllers/LobbyController.java index e907981b..ba4df70e 100644 --- a/backend/src/main/java/org/luxons/sevenwonders/controllers/LobbyController.java +++ b/backend/src/main/java/org/luxons/sevenwonders/controllers/LobbyController.java @@ -3,8 +3,8 @@ package org.luxons.sevenwonders.controllers; import java.security.Principal; import java.util.Collections; -import org.jsondoc.core.annotation.Api; -import org.jsondoc.core.annotation.ApiMethod; +import org.hildan.livedoc.core.annotation.Api; +import org.hildan.livedoc.core.annotation.ApiMethod; import org.luxons.sevenwonders.actions.ReorderPlayersAction; import org.luxons.sevenwonders.actions.UpdateSettingsAction; import org.luxons.sevenwonders.errors.ApiMisuseException; diff --git a/backend/src/main/java/org/luxons/sevenwonders/doc/GlobalDocumentation.java b/backend/src/main/java/org/luxons/sevenwonders/doc/GlobalDocumentation.java index b925c1cf..b1d64cab 100644 --- a/backend/src/main/java/org/luxons/sevenwonders/doc/GlobalDocumentation.java +++ b/backend/src/main/java/org/luxons/sevenwonders/doc/GlobalDocumentation.java @@ -1,7 +1,7 @@ package org.luxons.sevenwonders.doc; -import org.jsondoc.core.annotation.global.ApiGlobal; -import org.jsondoc.core.annotation.global.ApiGlobalSection; +import org.hildan.livedoc.core.annotation.global.ApiGlobal; +import org.hildan.livedoc.core.annotation.global.ApiGlobalSection; @ApiGlobal(sections = { @ApiGlobalSection(title = "First steps", paragraphs = {"Welcome to JsonDoc."}) diff --git a/backend/src/main/java/org/luxons/sevenwonders/doc/JsonDocController.java b/backend/src/main/java/org/luxons/sevenwonders/doc/JsonDocController.java deleted file mode 100644 index e9edde3e..00000000 --- a/backend/src/main/java/org/luxons/sevenwonders/doc/JsonDocController.java +++ /dev/null @@ -1,49 +0,0 @@ -package org.luxons.sevenwonders.doc; - -import java.util.Arrays; -import java.util.List; - -import org.jsondoc.core.annotation.Api; -import org.jsondoc.core.annotation.ApiMethod; -import org.jsondoc.core.pojo.JSONDoc; -import org.jsondoc.core.pojo.JSONDoc.MethodDisplay; -import org.jsondoc.core.scanner.JSONDocScanner; -import org.luxons.sevenwonders.doc.scanner.JsonDocWebSocketScanner; -import org.springframework.http.MediaType; -import org.springframework.stereotype.Controller; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestMethod; -import org.springframework.web.bind.annotation.ResponseBody; - -@Api(name = "SevenWonders API Documentation", - description = "This controller provides a JSON description of this documentation") -@Controller -public class JsonDocController { - - private String version; - - private String basePath; - - private List<String> packages; - - private JSONDocScanner jsondocScanner; - - private boolean playgroundEnabled = true; - - private MethodDisplay displayMethodAs = MethodDisplay.URI; - - public JsonDocController() { - this.version = "1.0.0"; - this.basePath = "http://localhost:8080"; - this.packages = Arrays.asList("org.luxons.sevenwonders.controllers", "org.luxons.sevenwonders.doc", - "org.luxons.sevenwonders.actions", "org.luxons.sevenwonders.game", "org.luxons.sevenwonders.lobby"); - this.jsondocScanner = new JsonDocWebSocketScanner(); - } - - @ApiMethod(description = "Get the Websocket API documentation for this game") - @RequestMapping(value = "/doc", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE) - @ResponseBody - public JSONDoc getApi() { - return jsondocScanner.getJSONDoc(version, basePath, packages, playgroundEnabled, displayMethodAs); - } -} 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 deleted file mode 100644 index 8a59451f..00000000 --- a/backend/src/main/java/org/luxons/sevenwonders/doc/builders/JSONDocApiObjectDocBuilder.java +++ /dev/null @@ -1,57 +0,0 @@ -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 deleted file mode 100644 index a1c9d7c6..00000000 --- a/backend/src/main/java/org/luxons/sevenwonders/doc/builders/JSONDocApiObjectFieldDocBuilder.java +++ /dev/null @@ -1,42 +0,0 @@ -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 deleted file mode 100644 index f518f319..00000000 --- a/backend/src/main/java/org/luxons/sevenwonders/doc/builders/JSONDocTemplateBuilder.java +++ /dev/null @@ -1,131 +0,0 @@ -package org.luxons.sevenwonders.doc.builders; - -import java.lang.reflect.Field; -import java.lang.reflect.Modifier; -import java.lang.reflect.Type; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.TreeSet; - -import org.jsondoc.core.annotation.ApiObjectField; -import org.jsondoc.core.pojo.JSONDocTemplate; -import org.jsondoc.core.util.JSONDocFieldWrapper; -import org.slf4j.Logger; -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 { - primitives.put(boolean.class, Boolean.class); - primitives.put(byte.class, Byte.class); - primitives.put(char.class, String.class); - primitives.put(double.class, Double.class); - primitives.put(float.class, Float.class); - primitives.put(int.class, Integer.class); - primitives.put(long.class, Long.class); - primitives.put(short.class, Short.class); - primitives.put(void.class, Void.class); - } - - public static JSONDocTemplate build(Class<?> clazz, Set<Class<?>> jsondocObjects) { - final JSONDocTemplate jsonDocTemplate = new JSONDocTemplate(); - - if (jsondocObjects.contains(clazz)) { - try { - Set<JSONDocFieldWrapper> fields = getAllDeclaredFields(clazz); - - for (JSONDocFieldWrapper jsondocFieldWrapper : fields) { - Field field = jsondocFieldWrapper.getField(); - String fieldName = field.getName(); - ApiObjectField apiObjectField = field.getAnnotation(ApiObjectField.class); - if (apiObjectField != null && !apiObjectField.name().isEmpty()) { - fieldName = apiObjectField.name(); - } - - 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())) { - value = getValue(Object.class, field.getGenericType(), fieldName, jsondocObjects); - } else { - value = getValue(field.getType(), field.getGenericType(), fieldName, jsondocObjects); - } - - jsonDocTemplate.put(fieldName, value); - } - } catch (Exception e) { - log.error("Error in JSONDocTemplate creation for class [" + clazz.getCanonicalName() + "]", e); - } - } - - return jsonDocTemplate; - } - - 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) { - Set<JSONDocFieldWrapper> fields = new TreeSet<JSONDocFieldWrapper>(); - - List<Field> declaredFields = new ArrayList<Field>(); - if (clazz.isEnum()) { - return fields; - } else { - declaredFields.addAll(Arrays.asList(clazz.getDeclaredFields())); - } - - for (Field field : declaredFields) { - if (!shouldBeSerialized(field)) { - continue; - } - if (field.isAnnotationPresent(ApiObjectField.class)) { - ApiObjectField annotation = field.getAnnotation(ApiObjectField.class); - fields.add(new JSONDocFieldWrapper(field, annotation.order())); - } else { - fields.add(new JSONDocFieldWrapper(field, Integer.MAX_VALUE)); - } - } - - if (clazz.getSuperclass() != null) { - fields.addAll(getAllDeclaredFields(clazz.getSuperclass())); - } - - return fields; - } - - private static boolean shouldBeSerialized(Field field) { - return !field.isSynthetic() && !Modifier.isTransient(field.getModifiers()); - } - - @SuppressWarnings("unchecked") - 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 deleted file mode 100644 index 4584e7cf..00000000 --- a/backend/src/main/java/org/luxons/sevenwonders/doc/builders/JSONDocTypeBuilder.java +++ /dev/null @@ -1,120 +0,0 @@ -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 deleted file mode 100644 index 46f38e8b..00000000 --- a/backend/src/main/java/org/luxons/sevenwonders/doc/builders/SpringObjectBuilder.java +++ /dev/null @@ -1,52 +0,0 @@ -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/SpringPathBuilder.java b/backend/src/main/java/org/luxons/sevenwonders/doc/builders/SpringPathBuilder.java deleted file mode 100644 index ca97fb41..00000000 --- a/backend/src/main/java/org/luxons/sevenwonders/doc/builders/SpringPathBuilder.java +++ /dev/null @@ -1,99 +0,0 @@ -package org.luxons.sevenwonders.doc.builders; - -import java.lang.annotation.Annotation; -import java.lang.reflect.Method; -import java.util.Arrays; -import java.util.Collections; -import java.util.HashSet; -import java.util.Set; - -import org.springframework.messaging.handler.annotation.MessageMapping; -import org.springframework.messaging.simp.annotation.SubscribeMapping; -import org.springframework.web.bind.annotation.RequestMapping; - -public class SpringPathBuilder { - - public static Set<String> buildPath(Method method) { - Set<String> paths = new HashSet<String>(); - - if (method.isAnnotationPresent(MessageMapping.class)) { - paths.addAll(getMappings(method, MessageMapping.class)); - } - if (method.isAnnotationPresent(SubscribeMapping.class)) { - paths.addAll(getMappings(method, SubscribeMapping.class)); - } - if (method.isAnnotationPresent(RequestMapping.class)) { - paths.addAll(getMappings(method, RequestMapping.class)); - } - - return paths; - } - - private static Set<String> getMappings(Method method, Class<? extends Annotation> annotationClass) { - Set<String> controllerMappings = getControllerMappings(method, annotationClass); - Set<String> methodMappings = getMappedPaths(method.getAnnotation(annotationClass)); - - Set<String> mappings = new HashSet<>(); - for (String controllerPath : controllerMappings) { - for (String methodPath : methodMappings) { - mappings.add(join(controllerPath, methodPath)); - } - } - return mappings; - } - - private static String join(String path1, String path2) { - boolean path1HasSep = path1.endsWith("/"); - boolean path2HasSep = path2.startsWith("/"); - if (path1HasSep && path2HasSep) { - return path1 + path2.substring(1); - } - if (!path1HasSep && !path2HasSep && (path1.isEmpty() || !path2.isEmpty())) { - return path1 + '/' + path2; - } - return path1 + path2; - } - - private static Set<String> getControllerMappings(Method method, Class<? extends Annotation> annotationClass) { - Class<?> controller = method.getDeclaringClass(); - if (controller.isAnnotationPresent(annotationClass)) { - return getMappedPaths(controller.getAnnotation(annotationClass)); - } - return Collections.singleton(""); - } - - private static Set<String> getMappedPaths(Annotation mapping) { - Set<String> paths = new HashSet<>(); - paths.addAll(Arrays.asList(valueMapping(mapping))); - paths.addAll(Arrays.asList(pathMapping(mapping))); - if (paths.isEmpty()) { - paths.add(""); - } - return paths; - } - - private static String[] pathMapping(Annotation mapping) { - try { - if (mapping instanceof RequestMapping) { - return ((RequestMapping) mapping).path(); - } - return new String[0]; - } catch (NoSuchMethodError e) { - //Handle the fact that this method is only in Spring 4, not available in Spring 3 - return new String[0]; - } - } - - private static String[] valueMapping(Annotation mapping) { - if (mapping instanceof RequestMapping) { - return ((RequestMapping) mapping).value(); - } - if (mapping instanceof MessageMapping) { - return ((MessageMapping) mapping).value(); - } - if (mapping instanceof SubscribeMapping) { - return ((SubscribeMapping) mapping).value(); - } - return new String[0]; - } -} diff --git a/backend/src/main/java/org/luxons/sevenwonders/doc/builders/SpringRequestBodyBuilder.java b/backend/src/main/java/org/luxons/sevenwonders/doc/builders/SpringRequestBodyBuilder.java deleted file mode 100644 index e3b20a81..00000000 --- a/backend/src/main/java/org/luxons/sevenwonders/doc/builders/SpringRequestBodyBuilder.java +++ /dev/null @@ -1,98 +0,0 @@ -package org.luxons.sevenwonders.doc.builders; - -import java.lang.annotation.Annotation; -import java.lang.reflect.Method; -import java.lang.reflect.Type; -import java.security.Principal; -import java.util.Arrays; -import java.util.List; - -import org.jsondoc.core.pojo.ApiBodyObjectDoc; -import org.jsondoc.core.util.JSONDocType; -import org.jsondoc.core.util.JSONDocTypeBuilder; -import org.jsondoc.core.util.JSONDocUtils; -import org.springframework.messaging.Message; -import org.springframework.messaging.MessageHeaders; -import org.springframework.messaging.handler.annotation.DestinationVariable; -import org.springframework.messaging.handler.annotation.Header; -import org.springframework.messaging.handler.annotation.Headers; -import org.springframework.messaging.handler.annotation.MessageMapping; -import org.springframework.messaging.handler.annotation.Payload; -import org.springframework.messaging.support.MessageHeaderAccessor; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; - -public class SpringRequestBodyBuilder { - - private static final List<Class<?>> NON_BODY_PARAM_TYPES = - Arrays.asList(MessageHeaders.class, MessageHeaderAccessor.class, Principal.class); - - private static final List<Class<? extends Annotation>> NON_BODY_PARAM_ANNOTATIONS = - Arrays.asList(Header.class, Headers.class, DestinationVariable.class); - - public static ApiBodyObjectDoc buildRequestBody(Method method) { - int index = getIndexOfBodyParam(method); - if (index < 0) { - return null; - } - final Class<?> bodyParamClass = method.getParameterTypes()[index]; - final Type bodyParamType = method.getGenericParameterTypes()[index]; - return new ApiBodyObjectDoc(JSONDocTypeBuilder.build(new JSONDocType(), bodyParamClass, bodyParamType)); - } - - public static int getIndexOfBodyParam(Method method) { - if (method.isAnnotationPresent(RequestMapping.class)) { - return getIndexOfBodyParamForRequestMapping(method); - } - if (method.isAnnotationPresent(MessageMapping.class)) { - return getIndexOfBodyParamForMessageMapping(method); - } - return -1; - } - - private static int getIndexOfBodyParamForRequestMapping(Method method) { - return JSONDocUtils.getIndexOfParameterWithAnnotation(method, RequestBody.class); - } - - private static int getIndexOfBodyParamForMessageMapping(Method method) { - Class<?>[] paramTypes = method.getParameterTypes(); - Annotation[][] paramAnnotations = method.getParameterAnnotations(); - for (int i = 0; i < paramTypes.length; i++) { - if (isBodyParam(paramTypes[i], paramAnnotations[i])) { - return i; - } - } - // no body param found - return -1; - } - - private static boolean isBodyParam(Class<?> paramType, Annotation[] paramAnnotations) { - if (paramType.equals(Message.class)) { - // it is too generic to be useful in the API doc even if it is indeed the body param - return false; - } - if (NON_BODY_PARAM_TYPES.contains(paramType)) { - return false; - } - for (Annotation paramAnnotation : paramAnnotations) { - // guarantees this param is the payload - if (paramAnnotation instanceof Payload) { - return true; - } - // guarantees this param is NOT the payload by definition of the annotation - if (isNonBodyParamAnnotation(paramAnnotation)) { - return false; - } - } - return true; - } - - private static boolean isNonBodyParamAnnotation(Annotation paramAnnotation) { - for (Class<? extends Annotation> annotation : NON_BODY_PARAM_ANNOTATIONS) { - if (annotation.isInstance(paramAnnotation)) { - return true; - } - } - return false; - } -} 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 deleted file mode 100644 index 4d8c0ed9..00000000 --- a/backend/src/main/java/org/luxons/sevenwonders/doc/builders/SpringResponseBuilder.java +++ /dev/null @@ -1,31 +0,0 @@ -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 deleted file mode 100644 index d7523577..00000000 --- a/backend/src/main/java/org/luxons/sevenwonders/doc/scanner/JsonDocWebSocketScanner.java +++ /dev/null @@ -1,156 +0,0 @@ -package org.luxons.sevenwonders.doc.scanner; - -import java.lang.reflect.Method; -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 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; -import org.jsondoc.core.scanner.builder.JSONDocApiMethodDocBuilder; -import org.jsondoc.core.util.JSONDocUtils; -import org.jsondoc.springmvc.scanner.Spring4JSONDocScanner; -import org.jsondoc.springmvc.scanner.builder.SpringConsumesBuilder; -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.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; -import org.reflections.util.ConfigurationBuilder; -import org.reflections.util.FilterBuilder; -import org.springframework.beans.BeanUtils; -import org.springframework.messaging.handler.annotation.MessageMapping; -import org.springframework.messaging.simp.annotation.SubscribeMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; - -public class JsonDocWebSocketScanner extends Spring4JSONDocScanner { - - @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(); - - log.debug("Found " + packages.size() + " package(s) to scan..."); - for (String pkg : packages) { - log.debug("Adding package to JSONDoc recursive scan: " + pkg); - urls.addAll(ClasspathHelper.forPackage(pkg)); - filter.includePackage(pkg); - } - - reflections = new Reflections(new ConfigurationBuilder().filterInputsBy(filter) - .setUrls(urls) - .addScanners(new MethodAnnotationsScanner())); - - JSONDoc jsondocDoc = new JSONDoc(version, basePath); - jsondocDoc.setPlaygroundEnabled(playgroundEnabled); - jsondocDoc.setDisplayMethodAs(displayMethodAs); - - jsondocControllers = jsondocControllers(); - jsondocObjects = jsondocObjects(packages); - jsondocFlows = jsondocFlows(); - jsondocGlobal = jsondocGlobal(); - jsondocChangelogs = jsondocChangelogs(); - jsondocMigrations = jsondocMigrations(); - - for (Class<?> clazz : jsondocObjects) { - jsondocTemplates.put(clazz, JSONDocTemplateBuilder.build(clazz, jsondocObjects)); - } - - jsondocDoc.setApis(getApiDocsMap(jsondocControllers, displayMethodAs)); - jsondocDoc.setObjects(getApiObjectsMap(jsondocObjects)); - jsondocDoc.setFlows(getApiFlowDocsMap(jsondocFlows, allApiMethodDocs)); - jsondocDoc.setGlobal(getApiGlobalDoc(jsondocGlobal, jsondocChangelogs, jsondocMigrations)); - - return jsondocDoc; - } - - @Override - public Set<Method> jsondocMethods(Class<?> controller) { - Set<Method> annotatedMethods = new LinkedHashSet<Method>(); - for (Method method : controller.getDeclaredMethods()) { - if (shouldDocument(method)) { - annotatedMethods.add(method); - } - } - return annotatedMethods; - } - - private boolean shouldDocument(Method method) { - return method.isAnnotationPresent(RequestMapping.class) || method.isAnnotationPresent(MessageMapping.class) - || method.isAnnotationPresent(SubscribeMapping.class); - } - - @Override - public ApiMethodDoc initApiMethodDoc(Method method, Map<Class<?>, JSONDocTemplate> jsondocTemplates) { - ApiMethodDoc apiMethodDoc = new ApiMethodDoc(); - apiMethodDoc.setPath(SpringPathBuilder.buildPath(method)); - apiMethodDoc.setMethod(method.getName()); - apiMethodDoc.setVerb(SpringVerbBuilder.buildVerb(method)); - apiMethodDoc.setProduces(SpringProducesBuilder.buildProduces(method)); - apiMethodDoc.setConsumes(SpringConsumesBuilder.buildConsumes(method)); - apiMethodDoc.setHeaders(SpringHeaderBuilder.buildHeaders(method)); - apiMethodDoc.setPathparameters(SpringPathVariableBuilder.buildPathVariable(method)); - apiMethodDoc.setQueryparameters(SpringQueryParamBuilder.buildQueryParams(method)); - apiMethodDoc.setBodyobject(SpringRequestBodyBuilder.buildRequestBody(method)); - apiMethodDoc.setResponse(SpringResponseBuilder.buildResponse(method)); - apiMethodDoc.setResponsestatuscode(SpringResponseStatusBuilder.buildResponseStatusCode(method)); - - Integer index = JSONDocUtils.getIndexOfParameterWithAnnotation(method, RequestBody.class); - if (index != -1) { - apiMethodDoc.getBodyobject().setJsondocTemplate(jsondocTemplates.get(method.getParameterTypes()[index])); - } - - return apiMethodDoc; - } - - @Override - public ApiMethodDoc mergeApiMethodDoc(Method method, ApiMethodDoc apiMethodDoc) { - if (method.isAnnotationPresent(ApiMethod.class) && method.getDeclaringClass().isAnnotationPresent(Api.class)) { - ApiMethodDoc jsondocApiMethodDoc = JSONDocApiMethodDocBuilder.build(method); - BeanUtils.copyProperties(jsondocApiMethodDoc, apiMethodDoc, "path", "verb", "produces", "consumes", - "headers", "pathparameters", "queryparameters", "bodyobject", "response", "responsestatuscode", - "apierrors", "supportedversions", "auth", "displayMethodAs"); - } - return apiMethodDoc; - } - - @Override - public Set<Class<?>> jsondocObjects(List<String> packages) { - return new ObjectsScanner(reflections).findJsondocObjects(packages); - } - - @Override - public ApiObjectDoc initApiObjectDoc(Class<?> clazz) { - return SpringObjectBuilder.buildObject(clazz); - } - - @Override - public ApiObjectDoc mergeApiObjectDoc(Class<?> clazz, ApiObjectDoc apiObjectDoc) { - if (clazz.isAnnotationPresent(ApiObject.class)) { - ApiObjectDoc jsondocApiObjectDoc = JSONDocApiObjectDocBuilder.build(clazz); - BeanUtils.copyProperties(jsondocApiObjectDoc, apiObjectDoc); - } - 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 deleted file mode 100644 index e20406ef..00000000 --- a/backend/src/main/java/org/luxons/sevenwonders/doc/scanner/ObjectsScanner.java +++ /dev/null @@ -1,209 +0,0 @@ -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; - } -} |