summaryrefslogtreecommitdiff
path: root/backend/src
diff options
context:
space:
mode:
authorJoffrey BION <joffrey.bion@gmail.com>2017-04-04 02:15:44 +0200
committerJoffrey BION <joffrey.bion@gmail.com>2017-04-04 02:15:44 +0200
commit262f9d19a4374c49d0e8e321b8094dac4ef743f2 (patch)
tree23345bbf25b92e9c43e1b8f6938f2c2e90c9e906 /backend/src
parentUpdate gradle wrapper to 3.4.1 (diff)
downloadseven-wonders-262f9d19a4374c49d0e8e321b8094dac4ef743f2.tar.gz
seven-wonders-262f9d19a4374c49d0e8e321b8094dac4ef743f2.tar.bz2
seven-wonders-262f9d19a4374c49d0e8e321b8094dac4ef743f2.zip
First draft of Jsondoc documentation generation
Diffstat (limited to 'backend/src')
-rw-r--r--backend/src/main/java/org/luxons/sevenwonders/SevenWonders.java2
-rw-r--r--backend/src/main/java/org/luxons/sevenwonders/actions/ChooseNameAction.java10
-rw-r--r--backend/src/main/java/org/luxons/sevenwonders/controllers/GameBrowserController.java6
-rw-r--r--backend/src/main/java/org/luxons/sevenwonders/controllers/GameController.java4
-rw-r--r--backend/src/main/java/org/luxons/sevenwonders/controllers/HomeController.java4
-rw-r--r--backend/src/main/java/org/luxons/sevenwonders/controllers/LobbyController.java6
-rw-r--r--backend/src/main/java/org/luxons/sevenwonders/doc/GlobalDocumentation.java10
-rw-r--r--backend/src/main/java/org/luxons/sevenwonders/doc/JsonDocController.java49
-rw-r--r--backend/src/main/java/org/luxons/sevenwonders/doc/builders/SpringPathBuilder.java99
-rw-r--r--backend/src/main/java/org/luxons/sevenwonders/doc/scanner/JsonDocWebSocketScanner.java151
-rw-r--r--backend/src/main/resources/application.properties11
11 files changed, 352 insertions, 0 deletions
diff --git a/backend/src/main/java/org/luxons/sevenwonders/SevenWonders.java b/backend/src/main/java/org/luxons/sevenwonders/SevenWonders.java
index 2c20c5d3..eba0c607 100644
--- a/backend/src/main/java/org/luxons/sevenwonders/SevenWonders.java
+++ b/backend/src/main/java/org/luxons/sevenwonders/SevenWonders.java
@@ -1,9 +1,11 @@
package org.luxons.sevenwonders;
+import org.jsondoc.spring.boot.starter.EnableJSONDoc;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
+@EnableJSONDoc
public class SevenWonders {
public static void main(String[] args) {
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 670e44ff..9b0ed42b 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,18 @@ 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;
+
+@ApiObject
+ (name = "Choose name action",
+ description = "The action to choose the player's name. This is the first action that should be called.",
+ group = "actions")
public class ChooseNameAction {
+ @ApiObjectField(description = "The display name of the player. May contain spaces and special characters.",
+ required = true,
+ format = ".{2,20}")
@NotNull
@Size(min = 2, max = 20)
private String playerName;
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 46e4531e..23b03127 100644
--- a/backend/src/main/java/org/luxons/sevenwonders/controllers/GameBrowserController.java
+++ b/backend/src/main/java/org/luxons/sevenwonders/controllers/GameBrowserController.java
@@ -4,6 +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.luxons.sevenwonders.actions.CreateGameAction;
import org.luxons.sevenwonders.actions.JoinGameAction;
import org.luxons.sevenwonders.errors.ApiMisuseException;
@@ -21,6 +23,7 @@ import org.springframework.messaging.simp.annotation.SubscribeMapping;
import org.springframework.stereotype.Controller;
import org.springframework.validation.annotation.Validated;
+@Api(name = "Game Browser", description = "This is the place where the player looks for a game")
@Controller
public class GameBrowserController {
@@ -43,12 +46,14 @@ public class GameBrowserController {
this.template = template;
}
+ @ApiMethod(description = "Created or updated games. List of existing games received here on subscribe.")
@SubscribeMapping("/games") // prefix /topic not shown
public Collection<Lobby> listGames(Principal principal) {
logger.info("Player '{}' subscribed to /topic/games", principal.getName());
return lobbyRepository.list();
}
+ @ApiMethod(description = "Create a new lobby.")
@MessageMapping("/lobby/create")
@SendToUser("/queue/lobby/joined")
public Lobby createGame(@Validated CreateGameAction action, Principal principal) {
@@ -66,6 +71,7 @@ public class GameBrowserController {
return lobby;
}
+ @ApiMethod(description = "Join an existing lobby.")
@MessageMapping("/lobby/join")
@SendToUser("/queue/lobby/joined")
public Lobby joinGame(@Validated JoinGameAction action, Principal principal) {
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 7b03a976..0ec631f6 100644
--- a/backend/src/main/java/org/luxons/sevenwonders/controllers/GameController.java
+++ b/backend/src/main/java/org/luxons/sevenwonders/controllers/GameController.java
@@ -2,6 +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.luxons.sevenwonders.actions.PrepareCardAction;
import org.luxons.sevenwonders.game.Game;
import org.luxons.sevenwonders.game.api.PlayerTurnInfo;
@@ -18,6 +20,7 @@ import org.springframework.messaging.handler.annotation.MessageMapping;
import org.springframework.messaging.simp.SimpMessagingTemplate;
import org.springframework.stereotype.Controller;
+@Api(name = "Game", description = "In-game events management")
@Controller
public class GameController {
@@ -33,6 +36,7 @@ public class GameController {
this.playerRepository = playerRepository;
}
+ @ApiMethod(description = "Prepares the user's card")
@MessageMapping("/game/{gameId}/prepare")
public void prepareCard(@DestinationVariable long gameId, PrepareCardAction action, Principal principal) {
Player player = playerRepository.find(principal.getName());
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 4ac236d3..dd6cad7f 100644
--- a/backend/src/main/java/org/luxons/sevenwonders/controllers/HomeController.java
+++ b/backend/src/main/java/org/luxons/sevenwonders/controllers/HomeController.java
@@ -2,6 +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.luxons.sevenwonders.actions.ChooseNameAction;
import org.luxons.sevenwonders.lobby.Player;
import org.luxons.sevenwonders.repositories.PlayerRepository;
@@ -13,6 +15,7 @@ import org.springframework.messaging.simp.annotation.SendToUser;
import org.springframework.stereotype.Controller;
import org.springframework.validation.annotation.Validated;
+@Api(name = "Home", description = "The home page of the game")
@Controller
public class HomeController {
@@ -25,6 +28,7 @@ public class HomeController {
this.playerRepository = playerRepository;
}
+ @ApiMethod(description = "Creates/updates the player's name (for the user's session)")
@MessageMapping("/chooseName")
@SendToUser("/queue/nameChoice")
public Player chooseName(@Validated ChooseNameAction action, Principal principal) {
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 839e27b9..b3345388 100644
--- a/backend/src/main/java/org/luxons/sevenwonders/controllers/LobbyController.java
+++ b/backend/src/main/java/org/luxons/sevenwonders/controllers/LobbyController.java
@@ -3,6 +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.luxons.sevenwonders.actions.ReorderPlayersAction;
import org.luxons.sevenwonders.actions.UpdateSettingsAction;
import org.luxons.sevenwonders.errors.ApiMisuseException;
@@ -17,6 +19,7 @@ import org.springframework.messaging.simp.SimpMessagingTemplate;
import org.springframework.stereotype.Controller;
import org.springframework.validation.annotation.Validated;
+@Api(name = "Lobby", description = "The place where players gather before a game")
@Controller
public class LobbyController {
@@ -32,6 +35,7 @@ public class LobbyController {
this.template = template;
}
+ @ApiMethod
@MessageMapping("/lobby/reorderPlayers")
public void reorderPlayers(@Validated ReorderPlayersAction action, Principal principal) {
Lobby lobby = getLobby(principal);
@@ -41,6 +45,7 @@ public class LobbyController {
sendLobbyUpdateToPlayers(lobby);
}
+ @ApiMethod
@MessageMapping("/lobby/updateSettings")
public void updateSettings(@Validated UpdateSettingsAction action, Principal principal) {
Lobby lobby = getLobby(principal);
@@ -55,6 +60,7 @@ public class LobbyController {
template.convertAndSend("/topic/games", Collections.singletonList(lobby));
}
+ @ApiMethod
@MessageMapping("/lobby/start")
public void startGame(Principal principal) {
Lobby lobby = getOwnedLobby(principal);
diff --git a/backend/src/main/java/org/luxons/sevenwonders/doc/GlobalDocumentation.java b/backend/src/main/java/org/luxons/sevenwonders/doc/GlobalDocumentation.java
new file mode 100644
index 00000000..b925c1cf
--- /dev/null
+++ b/backend/src/main/java/org/luxons/sevenwonders/doc/GlobalDocumentation.java
@@ -0,0 +1,10 @@
+package org.luxons.sevenwonders.doc;
+
+import org.jsondoc.core.annotation.global.ApiGlobal;
+import org.jsondoc.core.annotation.global.ApiGlobalSection;
+
+@ApiGlobal(sections = {
+ @ApiGlobalSection(title = "First steps", paragraphs = {"Welcome to JsonDoc."})
+})
+public class GlobalDocumentation {
+}
diff --git a/backend/src/main/java/org/luxons/sevenwonders/doc/JsonDocController.java b/backend/src/main/java/org/luxons/sevenwonders/doc/JsonDocController.java
new file mode 100644
index 00000000..383ae520
--- /dev/null
+++ b/backend/src/main/java/org/luxons/sevenwonders/doc/JsonDocController.java
@@ -0,0 +1,49 @@
+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");
+ 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)
+ public @ResponseBody
+ JSONDoc getApi() {
+ return jsondocScanner.getJSONDoc(version, basePath, packages, playgroundEnabled, displayMethodAs);
+ }
+}
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
new file mode 100644
index 00000000..ca97fb41
--- /dev/null
+++ b/backend/src/main/java/org/luxons/sevenwonders/doc/builders/SpringPathBuilder.java
@@ -0,0 +1,99 @@
+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/scanner/JsonDocWebSocketScanner.java b/backend/src/main/java/org/luxons/sevenwonders/doc/scanner/JsonDocWebSocketScanner.java
new file mode 100644
index 00000000..7dc0854e
--- /dev/null
+++ b/backend/src/main/java/org/luxons/sevenwonders/doc/scanner/JsonDocWebSocketScanner.java
@@ -0,0 +1,151 @@
+package org.luxons.sevenwonders.doc.scanner;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+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.pojo.ApiMethodDoc;
+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.SpringRequestBodyBuilder;
+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.SpringPathBuilder;
+import org.reflections.Reflections;
+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 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) {
+ Set<Method> methodsToDocument = getMethodsToDocument();
+
+ Set<Class<?>> candidates = Sets.newHashSet();
+ Set<Class<?>> subCandidates = Sets.newHashSet();
+
+ for (Method method : methodsToDocument) {
+ buildJSONDocObjectsCandidates(candidates, method.getReturnType(), method.getGenericReturnType(),
+ reflections);
+ Integer requestBodyParameterIndex =
+ JSONDocUtils.getIndexOfParameterWithAnnotation(method, RequestBody.class);
+ if (requestBodyParameterIndex != -1) {
+ candidates.addAll(
+ buildJSONDocObjectsCandidates(candidates, method.getParameterTypes()[requestBodyParameterIndex],
+ method.getGenericParameterTypes()[requestBodyParameterIndex], reflections));
+ }
+ }
+
+ // 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, reflections);
+ }
+
+ candidates.addAll(subCandidates);
+
+ return candidates.stream().filter(clazz -> inWhiteListedPackages(packages, clazz)).collect(Collectors.toSet());
+ }
+
+ 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, Reflections reflections) {
+ if (clazz.isPrimitive() || clazz.equals(Class.class)) {
+ return;
+ }
+
+ for (Field field : clazz.getDeclaredFields()) {
+ 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, reflections);
+ }
+ }
+ }
+ }
+}
diff --git a/backend/src/main/resources/application.properties b/backend/src/main/resources/application.properties
new file mode 100644
index 00000000..17c83826
--- /dev/null
+++ b/backend/src/main/resources/application.properties
@@ -0,0 +1,11 @@
+# mandatory configuration
+jsondoc.version=1.0
+jsondoc.basePath=http://localhost:8080
+jsondoc.packages[0]=org.luxons.sevenwonders
+#jsondoc.packages[1]=org.luxons.sevenwonders.doc
+#jsondoc.packages[2]=org.luxons.sevenwonders.controllers
+#jsondoc.packages[3]=org.luxons.sevenwonders.actions
+#jsondoc.packages[4]=org.luxons.sevenwonders.game
+# optional configuration
+jsondoc.playgroundEnabled=true
+jsondoc.displayMethodAs=URI
bgstack15