diff --git a/README.md b/README.md index ebfcfed5..d1ff65b4 100644 --- a/README.md +++ b/README.md @@ -315,6 +315,9 @@ Comparing to its Typescript counterpart, the Java library is still missing the f These features will be added in the future releases. ## Changelog +### v0.7.1 +- Fixed bug about having duplicate schema types with the same name. +- Improved minor code issues. ### v0.7.0 - Added ability to handle headers and params on webhook triggers. ### v0.6.0 diff --git a/commons/src/main/java/io/polyapi/commons/api/model/PolyFunction.java b/commons/src/main/java/io/polyapi/commons/api/model/PolyFunction.java index 508002b6..aade4a92 100644 --- a/commons/src/main/java/io/polyapi/commons/api/model/PolyFunction.java +++ b/commons/src/main/java/io/polyapi/commons/api/model/PolyFunction.java @@ -3,6 +3,7 @@ import java.lang.annotation.Retention; import java.lang.annotation.Target; +import static io.polyapi.commons.api.model.UpdateStrategy.PROJECT; import static java.lang.annotation.ElementType.METHOD; import static java.lang.annotation.RetentionPolicy.RUNTIME; @@ -41,4 +42,11 @@ * @return boolean The flag indicating if this function is to be deployed. */ boolean deployFunction() default true; + + /** + * The strategy to be used to update the function once it is deployed. By default, it delegates the strategy to the project. + * + * @return UpdateStrategy The strategy enum. + */ + UpdateStrategy updateStrategy() default PROJECT; } diff --git a/commons/src/main/java/io/polyapi/commons/api/model/UpdateStrategy.java b/commons/src/main/java/io/polyapi/commons/api/model/UpdateStrategy.java new file mode 100644 index 00000000..1188b410 --- /dev/null +++ b/commons/src/main/java/io/polyapi/commons/api/model/UpdateStrategy.java @@ -0,0 +1,21 @@ +package io.polyapi.commons.api.model; + +/** + * Enum that indicates how will the strategy to update to the latest versions of a function be. + */ +public enum UpdateStrategy { + /** + * The function will update to the latest version whenever it is redeployed. This safe version is recommended for final deployment of functions. + */ + MANUAL, + /** + * The function will update to the latest version whenever it is started. This unsafe version may fail suddenly if, for example, the server function is updated before being used and it changes the interface of the function. + * The advantage of this approach is that it doesn't require a redeployment for non-backwards compatibility changes on the function. + */ + AUTOMATIC, + + /** + * The function will delegate the strategy of redeployment to the project. If no project property is set, it will default to AUTOMATIC. + */ + PROJECT; +} diff --git a/commons/src/main/java/io/polyapi/commons/internal/json/JacksonJsonParser.java b/commons/src/main/java/io/polyapi/commons/internal/json/JacksonJsonParser.java index 7cca39ab..7d2c3e60 100644 --- a/commons/src/main/java/io/polyapi/commons/internal/json/JacksonJsonParser.java +++ b/commons/src/main/java/io/polyapi/commons/internal/json/JacksonJsonParser.java @@ -54,7 +54,7 @@ public String toJsonString(Object object) { try { log.debug("Parsing object of type {} to String.", object.getClass().getSimpleName()); String result = objectMapper.writeValueAsString(object); - log.debug("Parsing successful."); + log.debug("Object to String parsing successful."); if (log.isTraceEnabled()) { log.trace("Parsed result is:\n{}", result); } @@ -72,7 +72,7 @@ public InputStream toJsonInputStream(Object object) { try { log.debug("Parsing object of type {} to InputStream.", Optional.ofNullable(object).map(Object::getClass).map(Class::getName).orElse("null")); InputStream result = new ByteArrayInputStream(object == null ? new byte[]{} : objectMapper.writeValueAsBytes(object)); - log.debug("Parsing successful."); + log.debug("String to object parsing successful."); if (log.isTraceEnabled()) { log.trace("Parsed result is:\n{}", IOUtils.toString(result, defaultCharset())); log.trace("Resetting InputStream."); @@ -107,6 +107,7 @@ public O parseString(String json, Type expectedResponseType) { * @see JsonParser#parseInputStream(InputStream, Type) */ @Override + @SuppressWarnings("unchecked") public O parseInputStream(InputStream json, Type expectedResponseType) { try { if (log.isTraceEnabled()) { diff --git a/commons/src/main/java/io/polyapi/commons/internal/websocket/SocketIOWebSocketClient.java b/commons/src/main/java/io/polyapi/commons/internal/websocket/SocketIOWebSocketClient.java index c8a27373..4a2768cc 100644 --- a/commons/src/main/java/io/polyapi/commons/internal/websocket/SocketIOWebSocketClient.java +++ b/commons/src/main/java/io/polyapi/commons/internal/websocket/SocketIOWebSocketClient.java @@ -1,6 +1,16 @@ package io.polyapi.commons.internal.websocket; -import com.fasterxml.jackson.databind.type.TypeFactory; +import static java.lang.Boolean.FALSE; +import static java.lang.String.format; +import static java.util.concurrent.TimeUnit.MILLISECONDS; + +import java.lang.reflect.Type; +import java.net.URI; +import java.util.Map; +import java.util.Optional; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; + import io.polyapi.commons.api.error.parse.JsonToObjectParsingException; import io.polyapi.commons.api.error.websocket.EventRegistrationException; import io.polyapi.commons.api.error.websocket.WebsocketInputParsingException; @@ -13,19 +23,6 @@ import io.socket.client.Socket; import lombok.extern.slf4j.Slf4j; -import java.lang.reflect.Type; -import java.net.URI; -import java.util.HashMap; -import java.util.Map; -import java.util.Optional; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ExecutionException; - -import static java.lang.Boolean.FALSE; -import static java.lang.String.format; -import static java.util.concurrent.TimeUnit.MILLISECONDS; - - @Slf4j public class SocketIOWebSocketClient implements WebSocketClient { private final String url; @@ -35,7 +32,8 @@ public class SocketIOWebSocketClient implements WebSocketClient { private final JsonParser jsonParser; private Socket socket; - public SocketIOWebSocketClient(String url, String clientId, TokenProvider tokenProvider, JsonParser jsonParser, Long registrationTimeout) { + public SocketIOWebSocketClient(String url, String clientId, TokenProvider tokenProvider, JsonParser jsonParser, + Long registrationTimeout) { this.clientId = clientId; this.url = url; this.tokenProvider = tokenProvider; @@ -47,8 +45,8 @@ public SocketIOWebSocketClient(String url, String clientId, TokenProvider tokenP private synchronized Socket getSocket() { if (this.socket == null) { this.socket = IO.socket(URI.create(format("%s/events", url)), IO.Options.builder() - .setTransports(new String[]{"websocket"}) - .build()) + .setTransports(new String[] { "websocket" }) + .build()) .connect(); } return socket; @@ -59,14 +57,14 @@ public Handle registerTrigger(String event, String handleId, Type eventType, CompletableFuture completableFuture = new CompletableFuture() .orTimeout(registrationTimeout, MILLISECONDS); log.info("Registering event handler on server."); - getSocket().emit("registerWebhookEventHandler", new Object[]{Map.of("clientID", clientId, - "webhookHandleID", handleId, - "apiKey", tokenProvider.getToken())}, + getSocket().emit("registerWebhookEventHandler", new Object[] { Map.of("clientID", clientId, + "webhookHandleID", handleId, + "apiKey", tokenProvider.getToken()) }, objects -> { log.debug("Received response from server."); completableFuture.complete((boolean) Optional.ofNullable(objects[0]).orElse(FALSE)); }); - if (!completableFuture.get()) { + if (FALSE.equals(completableFuture.get())) { throw new EventRegistrationException(event, handleId); } String eventKey = format("%s:%s", event, handleId); @@ -93,7 +91,6 @@ public Handle registerAuthFunctionEventHandler(String id, PolyEventConsumer< return registerTrigger("", id, Object[].class, trigger); } - @Override public void close() { socket.disconnect(); diff --git a/library/src/main/java/io/polyapi/client/internal/proxy/PolyProxyFactory.java b/library/src/main/java/io/polyapi/client/internal/proxy/PolyProxyFactory.java index fcff8f4f..86b66507 100644 --- a/library/src/main/java/io/polyapi/client/internal/proxy/PolyProxyFactory.java +++ b/library/src/main/java/io/polyapi/client/internal/proxy/PolyProxyFactory.java @@ -66,6 +66,7 @@ public T createApiFunctionProxy(Class polyInterfa return createProxy(apiFunctionInvocationHandler, polyInterface); } + @SuppressWarnings("unchecked") public T createServerVariableProxy(String type, String packageName) { return (T) switch (type.toLowerCase()) { case "boolean" -> new Boolean(false); diff --git a/library/src/main/java/io/polyapi/client/internal/proxy/invocation/handler/PolyInvocationHandler.java b/library/src/main/java/io/polyapi/client/internal/proxy/invocation/handler/PolyInvocationHandler.java index c48679de..4c860358 100644 --- a/library/src/main/java/io/polyapi/client/internal/proxy/invocation/handler/PolyInvocationHandler.java +++ b/library/src/main/java/io/polyapi/client/internal/proxy/invocation/handler/PolyInvocationHandler.java @@ -8,7 +8,9 @@ import java.lang.reflect.Method; import java.util.HashMap; import java.util.Map; +import java.util.Arrays; +import static java.util.stream.Collectors.joining; import static java.util.stream.IntStream.range; @Slf4j @@ -26,10 +28,12 @@ public Object invoke(Object proxy, Method method, Object[] arguments) { var polyMetadata = method.getDeclaringClass().getAnnotation(PolyMetadata.class); log.debug("Executing method {} in proxy class {}.", method, proxy.getClass().getSimpleName()); log.debug("Executing Poly function with ID '{}'.", polyData.value()); - log.debug("Poly metadata param names: {}.", polyMetadata.paramNames()); - log.debug("Poly metadata param types: {}.", polyMetadata.paramTypes()); + + log.debug("Poly metadata param names: {}.", Arrays.stream(polyMetadata.paramNames()).collect(joining(","))); + log.debug("Poly metadata param types: {}.", Arrays.stream(polyMetadata.paramTypes()).collect(joining(","))); Map body = new HashMap<>(); - range(0, polyMetadata.paramNames().length).boxed().forEach(i -> body.put(polyMetadata.paramNames()[i], arguments[i])); + range(0, polyMetadata.paramNames().length).boxed() + .forEach(i -> body.put(polyMetadata.paramNames()[i], arguments[i])); return invocation.invoke(invokingClass, polyData.value(), body, method.getGenericReturnType()); } } diff --git a/library/src/main/java/io/polyapi/client/internal/proxy/invocation/handler/PolyTriggerInvocationHandler.java b/library/src/main/java/io/polyapi/client/internal/proxy/invocation/handler/PolyTriggerInvocationHandler.java index 8fc19048..aa0aaa5a 100644 --- a/library/src/main/java/io/polyapi/client/internal/proxy/invocation/handler/PolyTriggerInvocationHandler.java +++ b/library/src/main/java/io/polyapi/client/internal/proxy/invocation/handler/PolyTriggerInvocationHandler.java @@ -1,5 +1,9 @@ package io.polyapi.client.internal.proxy.invocation.handler; +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.Method; +import java.util.function.Consumer; + import io.polyapi.client.api.model.PolyEntity; import io.polyapi.client.api.model.PolyMetadata; import io.polyapi.client.error.PolyApiLibraryException; @@ -7,11 +11,6 @@ import io.polyapi.commons.api.websocket.WebSocketClient; import lombok.extern.slf4j.Slf4j; -import java.lang.reflect.InvocationHandler; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.util.function.Consumer; - @Slf4j public class PolyTriggerInvocationHandler implements InvocationHandler { @@ -22,9 +21,10 @@ public PolyTriggerInvocationHandler(WebSocketClient webSocketClient) { } @Override + @SuppressWarnings("unchecked") public Object invoke(Object proxy, Method method, Object[] args) { try { - PolyEventConsumer consumer = method.getParameterTypes()[0].equals(Consumer.class)? (payload, headers, params) -> Consumer.class.cast(args[0]).accept(payload) : PolyEventConsumer.class.cast(args[0]); + PolyEventConsumer consumer = method.getParameterTypes()[0].equals(Consumer.class)? (payload, headers, params) -> ((Consumer)args[0]).accept(payload) : PolyEventConsumer.class.cast(args[0]); Class invokingClass = method.getDeclaringClass(); var polyData = invokingClass.getAnnotation(PolyEntity.class); var polyMetadata = method.getDeclaringClass().getAnnotation(PolyMetadata.class); diff --git a/library/src/main/java/io/polyapi/client/internal/service/InvocationServiceImpl.java b/library/src/main/java/io/polyapi/client/internal/service/InvocationServiceImpl.java index a6f85a54..15733810 100644 --- a/library/src/main/java/io/polyapi/client/internal/service/InvocationServiceImpl.java +++ b/library/src/main/java/io/polyapi/client/internal/service/InvocationServiceImpl.java @@ -40,7 +40,8 @@ public class InvocationServiceImpl extends PolyApiService implements InvocationS private final JsonParser jsonParser; private final VariableInjectionService variableInjectionService; - public InvocationServiceImpl(String host, Integer port, String clientId, HttpClient client, JsonParser jsonParser, WebSocketClient webSocketClient, VariableInjectionService variableInjectionService) { + public InvocationServiceImpl(String host, Integer port, String clientId, HttpClient client, JsonParser jsonParser, + WebSocketClient webSocketClient, VariableInjectionService variableInjectionService) { super(host, port, client, jsonParser); this.clientId = clientId; this.jsonParser = jsonParser; @@ -49,47 +50,54 @@ public InvocationServiceImpl(String host, Integer port, String clientId, HttpCli } @Override - public T invokeServerFunction(Class invokingClass, String id, Map body, Type expectedResponseType) { + public T invokeServerFunction(Class invokingClass, String id, Map body, + Type expectedResponseType) { return invokeFunction("server", id, body, expectedResponseType); } @Override - public T invokeApiFunction(Class invokingClass, String id, Map body, Type expectedResponseType) { - ApiFunctionResponse response = invokeFunction("API", id, body, defaultInstance().constructParametricType(ApiFunctionResponse.class, defaultInstance().constructType(expectedResponseType))); + public T invokeApiFunction(Class invokingClass, String id, Map body, + Type expectedResponseType) { + ApiFunctionResponse response = invokeFunction("API", id, body, defaultInstance().constructParametricType( + ApiFunctionResponse.class, defaultInstance().constructType(expectedResponseType))); if (response.getStatus() < 200 || response.getStatus() >= 400) { - throw new UnexpectedHttpResponseException(new ResponseRecord(response.getHeaders().entrySet().stream().collect(Collectors.toMap(Map.Entry::getKey, entry -> List.of(entry.getValue()))), Optional.ofNullable(response.getData()).map(jsonParser::toJsonInputStream).orElse(null), response.getStatus())); + throw new UnexpectedHttpResponseException(new ResponseRecord( + response.getHeaders().entrySet().stream() + .collect(Collectors.toMap(Map.Entry::getKey, entry -> List.of(entry.getValue()))), + Optional.ofNullable(response.getData()).map(jsonParser::toJsonInputStream).orElse(null), + response.getStatus())); } return response.getData(); } @Override - public T invokeCustomFunction(Class invokingClass, String id, Map body, Type expectedResponseType) { + @SuppressWarnings("unchecked") + public T invokeCustomFunction(Class invokingClass, String id, Map body, + Type expectedResponseType) { try { - var delegateClass = Class.forName(format("%s.delegate.%s", invokingClass.getPackageName(), Optional.ofNullable(invokingClass.getDeclaredAnnotation(PolyMetadata.class)).map(PolyMetadata::delegate).filter(not(String::isBlank)).orElseGet(invokingClass::getSimpleName))); + var delegateClass = Class.forName(format("%s.delegate.%s", invokingClass.getPackageName(), + Optional.ofNullable(invokingClass.getDeclaredAnnotation(PolyMetadata.class)) + .map(PolyMetadata::delegate).filter(not(String::isBlank)) + .orElseGet(invokingClass::getSimpleName))); Object delegate; - try { - delegate = delegateClass.getConstructor().newInstance(); - } catch (NoSuchMethodException e) { - throw new MissingDefaultConstructorException(invokingClass.getName(), e); - } catch (InvocationTargetException | IllegalAccessException | InstantiationException e) { - throw new GeneratedClassInstantiationException(invokingClass.getName(), e); - } + delegate = delegateClass.getConstructor().newInstance(); var method = Stream.of(invokingClass.getDeclaredMethods()).findFirst() - .orElseThrow(() -> new PolyApiException()); + .orElseThrow(PolyApiException::new); try { return (T) Arrays.stream(delegateClass.getDeclaredMethods()) - .filter(declaredMethod -> - Optional.ofNullable(declaredMethod.getDeclaredAnnotation(PolyFunction.class)) - .filter(annotation -> annotation.type().equals(CLIENT)) - .filter(not(annotation -> annotation.name().isBlank())) - .filter(annotation -> annotation.name().equalsIgnoreCase(method.getName())) - .isPresent()) - .filter(declaredMethod -> declaredMethod.getParameterTypes().equals(method.getParameterTypes())) + .filter(declaredMethod -> Optional + .ofNullable(declaredMethod.getDeclaredAnnotation(PolyFunction.class)) + .filter(annotation -> annotation.type().equals(CLIENT)) + .filter(not(annotation -> annotation.name().isBlank())) + .filter(annotation -> annotation.name().equalsIgnoreCase(method.getName())) + .isPresent()) + .filter(declaredMethod -> Arrays.equals(declaredMethod.getParameterTypes(), method.getParameterTypes())) .findFirst() .orElseGet(() -> { try { - return delegateClass.getDeclaredMethod(method.getName(), method.getParameterTypes()); + return delegateClass.getDeclaredMethod(method.getName(), + method.getParameterTypes()); } catch (NoSuchMethodException e) { throw new InvalidMethodDeclarationException(invokingClass, e); } @@ -100,14 +108,18 @@ public T invokeCustomFunction(Class invokingClass, String id, Map invokingClass, String id, Map body, Type expectedResponseType) { + public Void invokeAuthFunction(Class invokingClass, String id, Map body, + Type expectedResponseType) { try { AuthTokenEventConsumer callback = AuthTokenEventConsumer.class.cast(body.remove("callback")); AuthTokenOptions options = AuthTokenOptions.class.cast(body.remove("options")); @@ -117,17 +129,19 @@ public Void invokeAuthFunction(Class invokingClass, String id, Map optionalOptions = Optional.ofNullable(options); - GetAuthTokenResponse data = post(format("auth-providers/%s/execute", id), replace(body), GetAuthTokenResponse.class); + GetAuthTokenResponse data = post(format("auth-providers/%s/execute", id), replace(body), + GetAuthTokenResponse.class); if (data.getToken() == null) { if (data.getUrl() == null || !optionalOptions.map(AuthTokenOptions::getAutoCloseOnUrl).orElse(false)) { Handle handle; handle = webSocketClient.registerAuthFunctionEventHandler(id, (payload, headers, params) -> { try { - GetAuthTokenResponse event = jsonParser.parseString(payload.toString(), GetAuthTokenResponse.class); + GetAuthTokenResponse event = jsonParser.parseString(payload.toString(), + GetAuthTokenResponse.class); if (event.getToken() != null) { callback.accept(event.getToken(), event.getUrl(), event.getError()); if (optionalOptions.map(AuthTokenOptions::getAutoCloseOnToken).orElse(true)) { - //handle.close(); + // handle.close(); } } } catch (RuntimeException e) { @@ -136,7 +150,8 @@ public Void invokeAuthFunction(Class invokingClass, String id, Map 0) { new Timer().schedule(new TimerTask() { @@ -162,7 +177,8 @@ public void run() { private T invokeFunction(String type, String id, Map body, Type expectedResponseType) { log.debug("Invoking Poly {} function with ID {}.", type, id); - var result = super., T>post(format("functions/%s/%s/execute", type.toLowerCase(), id), replace(body), expectedResponseType); + var result = super., T>post(format("functions/%s/%s/execute", type.toLowerCase(), id), + replace(body), expectedResponseType); log.debug("Function successfully executed. Returning result as {}.", expectedResponseType.getTypeName()); return result; } @@ -186,14 +202,17 @@ public void updateVariable(String id, T entity) { } @Override - public Void invokeSubresourceAuthFunction(Class invokingClass, String id, Map body, Type expectedResponseType) { + public Void invokeSubresourceAuthFunction(Class invokingClass, String id, Map body, + Type expectedResponseType) { body.put("clientID", clientId); - post(format("auth-providers/%s/%s", id, invokingClass.getDeclaredAnnotation(PolyAuthSubresource.class).value()), replace(body), expectedResponseType); + post(format("auth-providers/%s/%s", id, invokingClass.getDeclaredAnnotation(PolyAuthSubresource.class).value()), + replace(body), expectedResponseType); return null; } private Map replace(Map body) { - return body.entrySet().stream().collect(Collectors., String, Object>toMap(Map.Entry::getKey, entry -> variableInjectionService.replace(entry.getKey(), entry.getValue()))); + return body.entrySet().stream().collect(Collectors., String, Object>toMap( + Map.Entry::getKey, entry -> variableInjectionService.replace(entry.getKey(), entry.getValue()))); } } diff --git a/library/src/main/java/io/polyapi/client/internal/service/VariableInjectionServiceImpl.java b/library/src/main/java/io/polyapi/client/internal/service/VariableInjectionServiceImpl.java index e00fd79f..0b07a255 100644 --- a/library/src/main/java/io/polyapi/client/internal/service/VariableInjectionServiceImpl.java +++ b/library/src/main/java/io/polyapi/client/internal/service/VariableInjectionServiceImpl.java @@ -26,6 +26,7 @@ public Object replace(String propertyName, Object original) { .orElse(original); } + @SuppressWarnings({ "unchecked", "removal" }) public synchronized T inject(String key, String type) { log.debug("Injecting variable with key '{}' and type '{}'.", key, type); if (!injectionMap.containsKey(key)) { diff --git a/polyapi-maven-plugin/src/main/java/io/polyapi/plugin/model/function/CodeObject.java b/polyapi-maven-plugin/src/main/java/io/polyapi/plugin/model/function/CodeObject.java index 9fc7aab0..124a42b7 100644 --- a/polyapi-maven-plugin/src/main/java/io/polyapi/plugin/model/function/CodeObject.java +++ b/polyapi-maven-plugin/src/main/java/io/polyapi/plugin/model/function/CodeObject.java @@ -1,18 +1,9 @@ package io.polyapi.plugin.model.function; -import io.polyapi.commons.api.model.Visibility; import lombok.Getter; import lombok.Setter; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.Optional; - -import static java.lang.String.format; -import static java.util.stream.Collectors.joining; - @Getter @Setter public class CodeObject { diff --git a/polyapi-maven-plugin/src/main/java/io/polyapi/plugin/model/generation/Context.java b/polyapi-maven-plugin/src/main/java/io/polyapi/plugin/model/generation/Context.java index be7691a5..5f40f9fc 100644 --- a/polyapi-maven-plugin/src/main/java/io/polyapi/plugin/model/generation/Context.java +++ b/polyapi-maven-plugin/src/main/java/io/polyapi/plugin/model/generation/Context.java @@ -1,19 +1,22 @@ package io.polyapi.plugin.model.generation; -import io.polyapi.plugin.model.specification.Specification; -import lombok.Getter; -import lombok.Setter; -import lombok.extern.slf4j.Slf4j; - -import java.util.*; - import static io.polyapi.plugin.utils.StringUtils.toPascalCase; import static java.lang.String.format; import static java.util.function.Predicate.isEqual; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Objects; +import java.util.Optional; +import java.util.Set; + +import io.polyapi.plugin.model.specification.Specification; +import lombok.Getter; +import lombok.Setter; + @Getter @Setter -@Slf4j public class Context { private String name; private Context parent; @@ -26,7 +29,7 @@ public Context(Context parent, String name) { } public String getPackageName() { - return Optional.ofNullable(parent).map(parent -> format("%s.context.%s", parent.getPackageName(), parent.getName().toLowerCase())).orElse("io.polyapi"); + return Optional.ofNullable(parent).map(parentContext -> format("%s.context.%s", parentContext.getPackageName(), parentContext.getName().toLowerCase())).orElse("io.polyapi"); } public String getClassName() { diff --git a/polyapi-maven-plugin/src/main/java/io/polyapi/plugin/model/generation/CustomType.java b/polyapi-maven-plugin/src/main/java/io/polyapi/plugin/model/generation/CustomType.java index 1953a020..e41fd5c6 100644 --- a/polyapi-maven-plugin/src/main/java/io/polyapi/plugin/model/generation/CustomType.java +++ b/polyapi-maven-plugin/src/main/java/io/polyapi/plugin/model/generation/CustomType.java @@ -1,11 +1,10 @@ package io.polyapi.plugin.model.generation; +import static io.polyapi.plugin.utils.StringUtils.toPascalCase; + import io.polyapi.plugin.model.visitor.GenerableVisitor; -import io.polyapi.plugin.utils.StringUtils; import lombok.Getter; -import static io.polyapi.plugin.utils.StringUtils.toPascalCase; - @Getter public class CustomType implements Generable { private final String packageName; diff --git a/polyapi-maven-plugin/src/main/java/io/polyapi/plugin/model/generation/KeyValuePair.java b/polyapi-maven-plugin/src/main/java/io/polyapi/plugin/model/generation/KeyValuePair.java index 2c3fb966..1f4b8bd8 100644 --- a/polyapi-maven-plugin/src/main/java/io/polyapi/plugin/model/generation/KeyValuePair.java +++ b/polyapi-maven-plugin/src/main/java/io/polyapi/plugin/model/generation/KeyValuePair.java @@ -1,7 +1,6 @@ package io.polyapi.plugin.model.generation; import static io.polyapi.plugin.utils.StringUtils.toCamelCase; -import static io.polyapi.plugin.utils.StringUtils.toPascalCase; import static java.lang.String.format; public record KeyValuePair(K key, V value) { diff --git a/polyapi-maven-plugin/src/main/java/io/polyapi/plugin/model/specification/Specification.java b/polyapi-maven-plugin/src/main/java/io/polyapi/plugin/model/specification/Specification.java index 5ce2c466..25013772 100644 --- a/polyapi-maven-plugin/src/main/java/io/polyapi/plugin/model/specification/Specification.java +++ b/polyapi-maven-plugin/src/main/java/io/polyapi/plugin/model/specification/Specification.java @@ -1,27 +1,27 @@ package io.polyapi.plugin.model.specification; +import static io.polyapi.plugin.utils.StringUtils.toPascalCase; +import static java.lang.String.format; +import static java.util.function.Predicate.not; +import static java.util.stream.Collectors.joining; + +import java.util.Objects; +import java.util.Optional; +import java.util.stream.Stream; + import com.fasterxml.jackson.annotation.JsonSubTypes; import com.fasterxml.jackson.annotation.JsonTypeInfo; + import io.polyapi.plugin.model.specification.function.ApiFunctionSpecification; import io.polyapi.plugin.model.specification.function.AuthFunctionSpecification; import io.polyapi.plugin.model.specification.function.CustomFunctionSpecification; import io.polyapi.plugin.model.specification.function.ServerFunctionSpecification; -import io.polyapi.plugin.model.specification.webhook.WebhookHandleSpecification; import io.polyapi.plugin.model.specification.variable.ServerVariableSpecification; +import io.polyapi.plugin.model.specification.webhook.WebhookHandleSpecification; import io.polyapi.plugin.model.visitor.PolySpecificationVisitor; import lombok.Getter; import lombok.Setter; -import java.util.Objects; -import java.util.Optional; -import java.util.Set; -import java.util.stream.Stream; - -import static io.polyapi.plugin.utils.StringUtils.toPascalCase; -import static java.lang.String.format; -import static java.util.function.Predicate.not; -import static java.util.stream.Collectors.joining; - @Getter @Setter @JsonTypeInfo( diff --git a/polyapi-maven-plugin/src/main/java/io/polyapi/plugin/model/specification/function/FunctionSpecification.java b/polyapi-maven-plugin/src/main/java/io/polyapi/plugin/model/specification/function/FunctionSpecification.java index ae67400c..c9ef53d0 100644 --- a/polyapi-maven-plugin/src/main/java/io/polyapi/plugin/model/specification/function/FunctionSpecification.java +++ b/polyapi-maven-plugin/src/main/java/io/polyapi/plugin/model/specification/function/FunctionSpecification.java @@ -6,10 +6,6 @@ import lombok.Getter; import lombok.Setter; -import java.util.Set; - -import static java.lang.String.format; - @Getter @Setter public abstract class FunctionSpecification extends Specification { @@ -26,4 +22,31 @@ public String getSpecificationType() { public void accept(PolySpecificationVisitor visitor) { visitor.visit(this); } + + @Override + public int hashCode() { + final int prime = 31; + int result = super.hashCode(); + result = prime * result + ((function == null) ? 0 : function.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (!super.equals(obj)) + return false; + if (getClass() != obj.getClass()) + return false; + FunctionSpecification other = (FunctionSpecification) obj; + if (function == null) { + if (other.function != null) + return false; + } else if (!function.equals(other.function)) + return false; + return true; + } + + } diff --git a/polyapi-maven-plugin/src/main/java/io/polyapi/plugin/model/specification/resolved/ResolvedApiFunctionSpecification.java b/polyapi-maven-plugin/src/main/java/io/polyapi/plugin/model/specification/resolved/ResolvedApiFunctionSpecification.java index 61be7f75..7fdd81b7 100644 --- a/polyapi-maven-plugin/src/main/java/io/polyapi/plugin/model/specification/resolved/ResolvedApiFunctionSpecification.java +++ b/polyapi-maven-plugin/src/main/java/io/polyapi/plugin/model/specification/resolved/ResolvedApiFunctionSpecification.java @@ -1,10 +1,5 @@ package io.polyapi.plugin.model.specification.resolved; -import io.polyapi.plugin.model.generation.KeyValuePair; - -import java.util.List; -import java.util.Set; - public class ResolvedApiFunctionSpecification extends ResolvedDefaultFunctionSpecification { public ResolvedApiFunctionSpecification(ResolvedFunctionSpecification base) { super(base); diff --git a/polyapi-maven-plugin/src/main/java/io/polyapi/plugin/model/specification/resolved/ResolvedAuthFunctionSpecification.java b/polyapi-maven-plugin/src/main/java/io/polyapi/plugin/model/specification/resolved/ResolvedAuthFunctionSpecification.java index 6ed3ebc1..b5934e5f 100644 --- a/polyapi-maven-plugin/src/main/java/io/polyapi/plugin/model/specification/resolved/ResolvedAuthFunctionSpecification.java +++ b/polyapi-maven-plugin/src/main/java/io/polyapi/plugin/model/specification/resolved/ResolvedAuthFunctionSpecification.java @@ -1,10 +1,5 @@ package io.polyapi.plugin.model.specification.resolved; -import io.polyapi.plugin.model.generation.KeyValuePair; - -import java.util.List; -import java.util.Set; - public class ResolvedAuthFunctionSpecification extends ResolvedFunctionSpecification { public ResolvedAuthFunctionSpecification(ResolvedFunctionSpecification base) { super(base); diff --git a/polyapi-maven-plugin/src/main/java/io/polyapi/plugin/model/specification/resolved/ResolvedDefaultFunctionSpecification.java b/polyapi-maven-plugin/src/main/java/io/polyapi/plugin/model/specification/resolved/ResolvedDefaultFunctionSpecification.java index 40b63c5a..4507c984 100644 --- a/polyapi-maven-plugin/src/main/java/io/polyapi/plugin/model/specification/resolved/ResolvedDefaultFunctionSpecification.java +++ b/polyapi-maven-plugin/src/main/java/io/polyapi/plugin/model/specification/resolved/ResolvedDefaultFunctionSpecification.java @@ -1,19 +1,9 @@ package io.polyapi.plugin.model.specification.resolved; -import io.polyapi.plugin.model.generation.KeyValuePair; -import io.polyapi.plugin.utils.StringUtils; -import lombok.Getter; - -import java.util.ArrayList; import java.util.List; -import java.util.Optional; import java.util.Set; -import java.util.stream.Stream; -import static java.lang.String.format; -import static java.util.function.Predicate.isEqual; -import static java.util.function.Predicate.not; -import static java.util.stream.Collectors.joining; +import io.polyapi.plugin.model.generation.KeyValuePair; public class ResolvedDefaultFunctionSpecification extends ResolvedFunctionSpecification { diff --git a/polyapi-maven-plugin/src/main/java/io/polyapi/plugin/model/specification/resolved/ResolvedFunctionSpecification.java b/polyapi-maven-plugin/src/main/java/io/polyapi/plugin/model/specification/resolved/ResolvedFunctionSpecification.java index 211ae186..0dda19ee 100644 --- a/polyapi-maven-plugin/src/main/java/io/polyapi/plugin/model/specification/resolved/ResolvedFunctionSpecification.java +++ b/polyapi-maven-plugin/src/main/java/io/polyapi/plugin/model/specification/resolved/ResolvedFunctionSpecification.java @@ -1,21 +1,19 @@ package io.polyapi.plugin.model.specification.resolved; -import io.polyapi.plugin.model.generation.KeyValuePair; -import io.polyapi.plugin.model.type.basic.PlainPolyType; -import io.polyapi.plugin.utils.StringUtils; -import lombok.Getter; +import static java.lang.String.format; +import static java.util.function.Predicate.isEqual; +import static java.util.function.Predicate.not; +import static java.util.stream.Collectors.joining; import java.util.ArrayList; import java.util.List; import java.util.Optional; import java.util.Set; -import java.util.function.Predicate; import java.util.stream.Stream; -import static java.lang.String.format; -import static java.util.function.Predicate.isEqual; -import static java.util.function.Predicate.not; -import static java.util.stream.Collectors.joining; +import io.polyapi.plugin.model.generation.KeyValuePair; +import io.polyapi.plugin.utils.StringUtils; +import lombok.Getter; @Getter public class ResolvedFunctionSpecification extends ResolvedSpecification { diff --git a/polyapi-maven-plugin/src/main/java/io/polyapi/plugin/model/specification/resolved/ResolvedSpecification.java b/polyapi-maven-plugin/src/main/java/io/polyapi/plugin/model/specification/resolved/ResolvedSpecification.java index abc66f3d..a437a42a 100644 --- a/polyapi-maven-plugin/src/main/java/io/polyapi/plugin/model/specification/resolved/ResolvedSpecification.java +++ b/polyapi-maven-plugin/src/main/java/io/polyapi/plugin/model/specification/resolved/ResolvedSpecification.java @@ -1,15 +1,12 @@ package io.polyapi.plugin.model.specification.resolved; +import java.util.HashSet; +import java.util.Optional; +import java.util.Set; + import io.polyapi.plugin.model.generation.Generable; -import io.polyapi.plugin.model.generation.KeyValuePair; import lombok.Getter; -import java.util.*; -import java.util.stream.Stream; - -import static java.lang.String.format; -import static java.util.stream.Collectors.joining; - @Getter public class ResolvedSpecification implements Generable { private final String id; diff --git a/polyapi-maven-plugin/src/main/java/io/polyapi/plugin/model/specification/resolved/ResolvedSubresourceAuthFunctionSpecification.java b/polyapi-maven-plugin/src/main/java/io/polyapi/plugin/model/specification/resolved/ResolvedSubresourceAuthFunctionSpecification.java index de4b7b67..27fe81b4 100644 --- a/polyapi-maven-plugin/src/main/java/io/polyapi/plugin/model/specification/resolved/ResolvedSubresourceAuthFunctionSpecification.java +++ b/polyapi-maven-plugin/src/main/java/io/polyapi/plugin/model/specification/resolved/ResolvedSubresourceAuthFunctionSpecification.java @@ -1,10 +1,5 @@ package io.polyapi.plugin.model.specification.resolved; -import io.polyapi.plugin.model.generation.KeyValuePair; - -import java.util.List; -import java.util.Set; - public class ResolvedSubresourceAuthFunctionSpecification extends ResolvedAuthFunctionSpecification { public ResolvedSubresourceAuthFunctionSpecification(ResolvedFunctionSpecification base) { super(base); diff --git a/polyapi-maven-plugin/src/main/java/io/polyapi/plugin/model/specification/variable/PublicVariablePolyType.java b/polyapi-maven-plugin/src/main/java/io/polyapi/plugin/model/specification/variable/PublicVariablePolyType.java index 4b5a4f22..e7a10f93 100644 --- a/polyapi-maven-plugin/src/main/java/io/polyapi/plugin/model/specification/variable/PublicVariablePolyType.java +++ b/polyapi-maven-plugin/src/main/java/io/polyapi/plugin/model/specification/variable/PublicVariablePolyType.java @@ -1,5 +1,8 @@ package io.polyapi.plugin.model.specification.variable; +import lombok.Getter; + +@Getter public class PublicVariablePolyType extends VariablePolyType { private T value; diff --git a/polyapi-maven-plugin/src/main/java/io/polyapi/plugin/model/specification/webhook/WebhookHandleSpecification.java b/polyapi-maven-plugin/src/main/java/io/polyapi/plugin/model/specification/webhook/WebhookHandleSpecification.java index e8e1b824..67bae80f 100644 --- a/polyapi-maven-plugin/src/main/java/io/polyapi/plugin/model/specification/webhook/WebhookHandleSpecification.java +++ b/polyapi-maven-plugin/src/main/java/io/polyapi/plugin/model/specification/webhook/WebhookHandleSpecification.java @@ -1,7 +1,6 @@ package io.polyapi.plugin.model.specification.webhook; import io.polyapi.plugin.model.specification.Specification; -import io.polyapi.plugin.model.type.function.FunctionPolyType; import io.polyapi.plugin.model.type.function.FunctionSpecPolyType; import io.polyapi.plugin.model.visitor.PolySpecificationVisitor; import lombok.Getter; @@ -21,4 +20,29 @@ public String getSpecificationType() { public void accept(PolySpecificationVisitor visitor) { visitor.visit(this); } + + @Override + public int hashCode() { + final int prime = 31; + int result = super.hashCode(); + result = prime * result + ((function == null) ? 0 : function.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (!super.equals(obj)) + return false; + if (getClass() != obj.getClass()) + return false; + WebhookHandleSpecification other = (WebhookHandleSpecification) obj; + if (function == null) { + if (other.function != null) + return false; + } else if (!function.equals(other.function)) + return false; + return true; + } } diff --git a/polyapi-maven-plugin/src/main/java/io/polyapi/plugin/model/type/PolyType.java b/polyapi-maven-plugin/src/main/java/io/polyapi/plugin/model/type/PolyType.java index 7987935e..850b1623 100644 --- a/polyapi-maven-plugin/src/main/java/io/polyapi/plugin/model/type/PolyType.java +++ b/polyapi-maven-plugin/src/main/java/io/polyapi/plugin/model/type/PolyType.java @@ -2,6 +2,7 @@ import com.fasterxml.jackson.annotation.JsonSubTypes; import com.fasterxml.jackson.annotation.JsonTypeInfo; + import io.polyapi.commons.api.model.PolyObject; import io.polyapi.plugin.model.type.basic.ArrayPolyType; import io.polyapi.plugin.model.type.basic.PlainPolyType; @@ -13,9 +14,6 @@ import lombok.Getter; import lombok.Setter; -import static java.lang.String.format; -import static java.util.stream.Collectors.joining; - @JsonTypeInfo( use = JsonTypeInfo.Id.NAME, property = "kind", diff --git a/polyapi-maven-plugin/src/main/java/io/polyapi/plugin/model/type/PropertyPolyType.java b/polyapi-maven-plugin/src/main/java/io/polyapi/plugin/model/type/PropertyPolyType.java index 1579c0b8..0194c36d 100644 --- a/polyapi-maven-plugin/src/main/java/io/polyapi/plugin/model/type/PropertyPolyType.java +++ b/polyapi-maven-plugin/src/main/java/io/polyapi/plugin/model/type/PropertyPolyType.java @@ -5,14 +5,6 @@ import lombok.Getter; import lombok.Setter; -import java.lang.reflect.ParameterizedType; -import java.lang.reflect.Type; -import java.util.Arrays; -import java.util.Set; - -import static java.lang.String.format; -import static java.util.stream.Collectors.joining; - @Getter @Setter public class PropertyPolyType implements PolyObject { diff --git a/polyapi-maven-plugin/src/main/java/io/polyapi/plugin/model/type/complex/ObjectPolyType.java b/polyapi-maven-plugin/src/main/java/io/polyapi/plugin/model/type/complex/ObjectPolyType.java index 3525b32f..28ee6f4e 100644 --- a/polyapi-maven-plugin/src/main/java/io/polyapi/plugin/model/type/complex/ObjectPolyType.java +++ b/polyapi-maven-plugin/src/main/java/io/polyapi/plugin/model/type/complex/ObjectPolyType.java @@ -1,25 +1,25 @@ package io.polyapi.plugin.model.type.complex; +import java.util.List; + import com.fasterxml.jackson.databind.annotation.JsonDeserialize; + import io.polyapi.commons.internal.json.RawValueDeserializer; import io.polyapi.plugin.model.type.PolyType; import io.polyapi.plugin.model.type.PropertyPolyType; import io.polyapi.plugin.model.visitor.TypeVisitor; import lombok.Getter; import lombok.Setter; -import lombok.extern.slf4j.Slf4j; - -import java.util.List; @Getter @Setter -@Slf4j public class ObjectPolyType extends PolyType implements PropertiesObjectPolyType, SchemaObjectPolyType, MapObjectPolyType { @JsonDeserialize(using = RawValueDeserializer.class) private String schema; private List properties; private String typeName; + @Override public void accept(TypeVisitor visitor) { if (schema == null) { if (properties == null) { diff --git a/polyapi-maven-plugin/src/main/java/io/polyapi/plugin/model/type/primitive/PrimitivePolyType.java b/polyapi-maven-plugin/src/main/java/io/polyapi/plugin/model/type/primitive/PrimitivePolyType.java index 8d981804..94a812f4 100644 --- a/polyapi-maven-plugin/src/main/java/io/polyapi/plugin/model/type/primitive/PrimitivePolyType.java +++ b/polyapi-maven-plugin/src/main/java/io/polyapi/plugin/model/type/primitive/PrimitivePolyType.java @@ -5,14 +5,12 @@ import lombok.Getter; import lombok.Setter; -import java.util.HashSet; -import java.util.Set; - @Getter @Setter public class PrimitivePolyType extends PolyType { private PrimitiveTypeValue type; + @Override public void accept(TypeVisitor visitor) { visitor.visit(this); } diff --git a/polyapi-maven-plugin/src/main/java/io/polyapi/plugin/model/visitor/GenerableVisitor.java b/polyapi-maven-plugin/src/main/java/io/polyapi/plugin/model/visitor/GenerableVisitor.java index c58ddd69..75351d99 100644 --- a/polyapi-maven-plugin/src/main/java/io/polyapi/plugin/model/visitor/GenerableVisitor.java +++ b/polyapi-maven-plugin/src/main/java/io/polyapi/plugin/model/visitor/GenerableVisitor.java @@ -1,12 +1,11 @@ package io.polyapi.plugin.model.visitor; -import io.polyapi.plugin.model.generation.CustomType; -import io.polyapi.plugin.model.generation.Generable; -import io.polyapi.plugin.model.generation.Context; -import io.polyapi.plugin.model.specification.Specification; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import io.polyapi.plugin.model.generation.CustomType; +import io.polyapi.plugin.model.generation.Generable; + public interface GenerableVisitor extends PolySpecificationVisitor { Logger log = LoggerFactory.getLogger(GenerableVisitor.class); diff --git a/polyapi-maven-plugin/src/main/java/io/polyapi/plugin/mojo/DeployFunctionsMojo.java b/polyapi-maven-plugin/src/main/java/io/polyapi/plugin/mojo/DeployFunctionsMojo.java index 8af4cb3a..e2b22be1 100644 --- a/polyapi-maven-plugin/src/main/java/io/polyapi/plugin/mojo/DeployFunctionsMojo.java +++ b/polyapi-maven-plugin/src/main/java/io/polyapi/plugin/mojo/DeployFunctionsMojo.java @@ -4,6 +4,7 @@ import io.polyapi.commons.api.model.PolyFunction; import io.polyapi.commons.api.model.RequiredDependencies; import io.polyapi.commons.api.model.RequiredDependency; +import io.polyapi.commons.api.model.UpdateStrategy; import io.polyapi.plugin.error.PolyApiMavenPluginException; import io.polyapi.plugin.error.deploy.DeploymentWrapperException; import io.polyapi.plugin.model.function.CodeObject; @@ -44,18 +45,20 @@ public class DeployFunctionsMojo extends PolyApiMojo { @org.apache.maven.plugins.annotations.Parameter(property = "functions") private String functions; + @org.apache.maven.plugins.annotations.Parameter(property = "update.strategy", defaultValue = "AUTOMATIC") + private UpdateStrategy defaultUpdateStrategy; @Override protected void execute(String host, Integer port) { PolyFunctionService polyFunctionService = new PolyFunctionServiceImpl(host, port, getHttpClient(), getJsonParser()); log.info("Initiating the deployment of functions."); Map exceptions = new HashMap<>(); - Predicate filter = null; + Predicate filter; if (isBlank(functions)) { log.debug("No specific functions to deploy were declared."); filter = method -> true; } else { - filter = method -> Arrays.stream(functions.split(",")).map(String::trim).peek(functionName -> log.debug("Looking for function {} to deploy.", functionName)).anyMatch(name -> { + filter = method -> Arrays.stream(functions.split(",")).map(String::trim).anyMatch(name -> { PolyFunction annotation = method.getAnnotation(PolyFunction.class); String functionName = Optional.ofNullable(annotation.name()).filter(not(String::isBlank)).orElseGet(method::getName); return functionName.equals(name) || format("%s.%s", Optional.ofNullable(annotation.context()).filter(not(String::isBlank)).orElseGet(method.getDeclaringClass()::getPackageName), functionName).equals(name); @@ -118,7 +121,7 @@ protected void execute(String host, Integer port) { log.error("{} Errors occurred while deploying a total of {} functions.", exceptions.size(), methods.size()); exceptions.forEach((polyFunctionMetadata, exception) -> { try { - log.error(IOUtils.toString(HttpResponseException.class.cast(exception).getResponse().body())); + log.error(IOUtils.toString(HttpResponseException.class.cast(exception).getResponse().body(), defaultCharset())); } catch (IOException e) { throw new RuntimeException(e); } diff --git a/polyapi-maven-plugin/src/main/java/io/polyapi/plugin/service/MavenService.java b/polyapi-maven-plugin/src/main/java/io/polyapi/plugin/service/MavenService.java index a5de1120..b7674b24 100644 --- a/polyapi-maven-plugin/src/main/java/io/polyapi/plugin/service/MavenService.java +++ b/polyapi-maven-plugin/src/main/java/io/polyapi/plugin/service/MavenService.java @@ -1,47 +1,52 @@ package io.polyapi.plugin.service; -import io.polyapi.commons.api.model.PolyFunction; -import io.polyapi.commons.api.model.PolyGeneratedClass; -import io.polyapi.commons.api.model.RequiredDependencies; -import io.polyapi.commons.api.model.RequiredDependency; -import io.polyapi.plugin.error.PolyApiMavenPluginException; -import io.polyapi.plugin.error.validation.PropertyNotFoundException; -import lombok.extern.slf4j.Slf4j; -import org.apache.maven.artifact.DependencyResolutionRequiredException; -import org.apache.maven.model.Plugin; -import org.apache.maven.model.PluginExecution; -import org.apache.maven.project.MavenProject; -import org.codehaus.plexus.util.xml.Xpp3Dom; -import org.reflections.Reflections; -import org.reflections.util.ConfigurationBuilder; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import static java.lang.String.format; +import static java.util.function.Predicate.not; +import static java.util.regex.Pattern.compile; +import static java.util.stream.Collectors.joining; +import static java.util.stream.Collectors.toSet; +import static java.util.stream.Stream.concat; +import static javax.lang.model.SourceVersion.isKeyword; +import static org.reflections.scanners.Scanners.MethodsAnnotated; -import javax.lang.model.SourceVersion; import java.io.File; import java.lang.reflect.Method; import java.net.MalformedURLException; import java.net.URL; import java.net.URLClassLoader; -import java.util.*; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Objects; +import java.util.Optional; +import java.util.Set; import java.util.function.Consumer; import java.util.function.Predicate; import java.util.regex.Pattern; import java.util.stream.Stream; -import static java.lang.String.format; -import static java.util.function.Predicate.not; -import static java.util.regex.Pattern.compile; -import static java.util.stream.Collectors.joining; -import static java.util.stream.Collectors.toSet; -import static java.util.stream.Stream.concat; -import static javax.lang.model.SourceVersion.isKeyword; -import static org.reflections.scanners.Scanners.MethodsAnnotated; +import javax.lang.model.SourceVersion; + +import org.apache.maven.artifact.DependencyResolutionRequiredException; +import org.apache.maven.model.Plugin; +import org.apache.maven.model.PluginExecution; +import org.apache.maven.project.MavenProject; +import org.codehaus.plexus.util.xml.Xpp3Dom; +import org.reflections.Reflections; +import org.reflections.util.ConfigurationBuilder; + +import io.polyapi.commons.api.model.PolyFunction; +import io.polyapi.commons.api.model.PolyGeneratedClass; +import io.polyapi.commons.api.model.RequiredDependencies; +import io.polyapi.commons.api.model.RequiredDependency; +import io.polyapi.plugin.error.PolyApiMavenPluginException; +import io.polyapi.plugin.error.validation.PropertyNotFoundException; +import lombok.extern.slf4j.Slf4j; @Slf4j public class MavenService { - private static final String FUNCTION_NAME_PATTERN = "^[a-z][\\w$_]+$"; - private static final String CONTEXT_PATTERN = "^[a-z][\\w$_.]*[\\w$_]$"; + private static final String FUNCTION_NAME_PATTERN = "^[a-z][\\w$]*$"; + private static final String CONTEXT_PATTERN = "^[a-z][\\w$.]*[\\w$]$"; private final MavenProject project; public MavenService(MavenProject project) { @@ -66,19 +71,21 @@ public String getPropertyFromPlugin(String pluginGroupId, String pluginArtifactI return plugins.stream() .filter(plugin -> pluginGroupId.equals(plugin.getGroupId())) .filter(plugin -> pluginArtifactId.equals(plugin.getArtifactId())) - .peek(plugin -> log.debug("Found match: {}.{}:{}.\nRetrieving executions.", plugin.getGroupId(), plugin.getArtifactId(), plugin.getVersion())) - .map(Plugin::getExecutions) - .peek(pluginExecutions -> log.debug("Found {} executions.", pluginExecutions.size())) - .flatMap(List::stream) + .flatMap(plugin -> { + log.debug("Found match: {}.{}:{}.\nRetrieving executions.", plugin.getGroupId(), plugin.getArtifactId(), plugin.getVersion()); + List executions = Optional.ofNullable(plugin.getExecutions()).orElseGet(ArrayList::new); + log.debug("Found {} executions.", executions.size()); + return executions.stream(); + }) .map(PluginExecution::getConfiguration) .filter(Objects::nonNull) .map(Xpp3Dom.class::cast) - .peek(configuration -> log.debug("Found configuration within the execution. Retrieving children.")) - .map(Xpp3Dom::getChildren) - .peek(children -> log.debug("Found {} children properties.", children.length)) - .flatMap(Stream::of) - .filter(Objects::nonNull) - .peek(property -> log.debug("Property '{}' found.", propertyName)) + .flatMap(configuration -> { + log.debug("Found configuration within the execution. Retrieving children."); + Xpp3Dom[] children = Optional.ofNullable(configuration.getChildren()).orElse(new Xpp3Dom[]{}); + log.debug("Found {} children properties.", children.length); + return Arrays.stream(children); + }) .map(Xpp3Dom::getValue) .findFirst() .orElseThrow(() -> new PropertyNotFoundException(propertyName)); @@ -89,7 +96,6 @@ public URLClassLoader getProjectClassLoader() { return new URLClassLoader(concat(concat(project.getCompileClasspathElements().stream(), project.getRuntimeClasspathElements().stream()), Stream.of(project.getBuild().getOutputDirectory())) - .peek(classLoadingPath -> log.debug(" Adding classloading path '{}'.", classLoadingPath)) .map(File::new) .map(File::toURI) .map(uri -> { @@ -103,13 +109,12 @@ public URLClassLoader getProjectClassLoader() { .toArray(URL[]::new), MavenService.class.getClassLoader()); } catch (DependencyResolutionRequiredException e) { - throw new RuntimeException(e); + throw new RuntimeException(e); // FIXME: Throw the appropriate exception. } } public List getSourceFolders() { return concat(project.getCompileSourceRoots().stream(), Stream.of(project.getBasedir() + "/target/generated-sources")) - .peek(sourceRoot -> log.debug(" Retrieving source root '{}'", sourceRoot)) .map(File::new) .filter(File::exists) .toList(); @@ -119,7 +124,6 @@ public List getJarSources() { try { return project.getCompileClasspathElements().stream() .filter(path -> path.endsWith(".jar")) - .peek(path -> log.debug(" Retrieving jar sources from '{}'.", path)) .toList(); } catch (DependencyResolutionRequiredException e) { // FIXME: Throw appropriate exception. diff --git a/polyapi-maven-plugin/src/main/java/io/polyapi/plugin/service/PolyCodeWriter.java b/polyapi-maven-plugin/src/main/java/io/polyapi/plugin/service/PolyCodeWriter.java index e8a3998f..bf602586 100644 --- a/polyapi-maven-plugin/src/main/java/io/polyapi/plugin/service/PolyCodeWriter.java +++ b/polyapi-maven-plugin/src/main/java/io/polyapi/plugin/service/PolyCodeWriter.java @@ -1,10 +1,7 @@ package io.polyapi.plugin.service; -import com.sun.codemodel.CodeWriter; -import com.sun.codemodel.JPackage; -import lombok.extern.slf4j.Slf4j; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import static java.nio.charset.Charset.defaultCharset; +import static java.util.stream.Collectors.toMap; import java.io.ByteArrayOutputStream; import java.io.FilterOutputStream; @@ -13,8 +10,10 @@ import java.util.HashMap; import java.util.Map; -import static java.nio.charset.Charset.defaultCharset; -import static java.util.stream.Collectors.toMap; +import com.sun.codemodel.CodeWriter; +import com.sun.codemodel.JPackage; + +import lombok.extern.slf4j.Slf4j; @Slf4j public class PolyCodeWriter extends CodeWriter implements AutoCloseable { @@ -26,6 +25,7 @@ public OutputStream openBinary(JPackage pkg, String fileName) throws IOException var outputStream = new ByteArrayOutputStream(); outputStreams.put(fileName.replace(".java", ""), outputStream); return new FilterOutputStream(outputStream) { + @Override public void close() { // don't let this stream close } diff --git a/polyapi-maven-plugin/src/main/java/io/polyapi/plugin/service/SpecificationServiceImpl.java b/polyapi-maven-plugin/src/main/java/io/polyapi/plugin/service/SpecificationServiceImpl.java index 15582ee2..e7ca3d2a 100644 --- a/polyapi-maven-plugin/src/main/java/io/polyapi/plugin/service/SpecificationServiceImpl.java +++ b/polyapi-maven-plugin/src/main/java/io/polyapi/plugin/service/SpecificationServiceImpl.java @@ -1,24 +1,19 @@ package io.polyapi.plugin.service; +import static com.fasterxml.jackson.databind.type.TypeFactory.defaultInstance; +import static java.lang.String.format; +import static java.util.stream.Collectors.joining; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + import io.polyapi.commons.api.http.HttpClient; import io.polyapi.commons.api.json.JsonParser; import io.polyapi.commons.api.service.PolyApiService; import io.polyapi.plugin.model.specification.Specification; import io.polyapi.plugin.model.specification.function.ServerFunctionSpecification; import lombok.extern.slf4j.Slf4j; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.stream.Collectors; - -import static com.fasterxml.jackson.databind.type.TypeFactory.defaultInstance; -import static java.lang.String.format; -import static java.util.function.Function.identity; -import static java.util.stream.Collectors.joining; @Slf4j public class SpecificationServiceImpl extends PolyApiService implements SpecificationService { diff --git a/polyapi-maven-plugin/src/main/java/io/polyapi/plugin/service/generation/PolyObjectResolverService.java b/polyapi-maven-plugin/src/main/java/io/polyapi/plugin/service/generation/PolyObjectResolverService.java index 5b202837..82ea9319 100644 --- a/polyapi-maven-plugin/src/main/java/io/polyapi/plugin/service/generation/PolyObjectResolverService.java +++ b/polyapi-maven-plugin/src/main/java/io/polyapi/plugin/service/generation/PolyObjectResolverService.java @@ -1,10 +1,34 @@ package io.polyapi.plugin.service.generation; +import static java.lang.String.format; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Optional; +import java.util.Set; +import java.util.function.Function; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.stream.IntStream; + import io.polyapi.plugin.model.generation.Context; import io.polyapi.plugin.model.generation.KeyValuePair; import io.polyapi.plugin.model.generation.ResolvedContext; -import io.polyapi.plugin.model.specification.function.*; -import io.polyapi.plugin.model.specification.resolved.*; +import io.polyapi.plugin.model.specification.function.ApiFunctionSpecification; +import io.polyapi.plugin.model.specification.function.AuthFunctionSpecification; +import io.polyapi.plugin.model.specification.function.CustomFunctionSpecification; +import io.polyapi.plugin.model.specification.function.FunctionSpecification; +import io.polyapi.plugin.model.specification.function.ServerFunctionSpecification; +import io.polyapi.plugin.model.specification.resolved.ResolvedApiFunctionSpecification; +import io.polyapi.plugin.model.specification.resolved.ResolvedAuthFunctionSpecification; +import io.polyapi.plugin.model.specification.resolved.ResolvedCustomFunctionSpecification; +import io.polyapi.plugin.model.specification.resolved.ResolvedFunctionSpecification; +import io.polyapi.plugin.model.specification.resolved.ResolvedServerFunctionSpecification; +import io.polyapi.plugin.model.specification.resolved.ResolvedServerVariableSpecification; +import io.polyapi.plugin.model.specification.resolved.ResolvedStandardAuthFunctionSpecification; +import io.polyapi.plugin.model.specification.resolved.ResolvedSubresourceAuthFunctionSpecification; +import io.polyapi.plugin.model.specification.resolved.ResolvedWebhookHandleSpecification; import io.polyapi.plugin.model.specification.variable.ServerVariableSpecification; import io.polyapi.plugin.model.specification.webhook.WebhookHandleSpecification; import io.polyapi.plugin.model.type.PropertyPolyType; @@ -15,16 +39,6 @@ import io.polyapi.plugin.service.visitor.PolyObjectResolverVisitor; import io.polyapi.plugin.service.visitor.TypeExtractionVisitor; import lombok.extern.slf4j.Slf4j; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.util.*; -import java.util.function.Function; -import java.util.regex.Matcher; -import java.util.regex.Pattern; -import java.util.stream.IntStream; - -import static java.lang.String.format; @Slf4j public class PolyObjectResolverService { diff --git a/polyapi-maven-plugin/src/main/java/io/polyapi/plugin/service/schema/JsonSchemaNameHelper.java b/polyapi-maven-plugin/src/main/java/io/polyapi/plugin/service/schema/JsonSchemaNameHelper.java index 895de465..31dac47c 100644 --- a/polyapi-maven-plugin/src/main/java/io/polyapi/plugin/service/schema/JsonSchemaNameHelper.java +++ b/polyapi-maven-plugin/src/main/java/io/polyapi/plugin/service/schema/JsonSchemaNameHelper.java @@ -3,14 +3,13 @@ import org.jsonschema2pojo.GenerationConfig; import org.jsonschema2pojo.util.NameHelper; -import java.util.regex.Pattern; - public class JsonSchemaNameHelper extends NameHelper { public JsonSchemaNameHelper(GenerationConfig generationConfig) { super(generationConfig); } + @Override public String replaceIllegalCharacters(String name) { - return super.replaceIllegalCharacters(name.replaceAll("\\+", "Plus").replaceAll("-", "Minus")); + return super.replaceIllegalCharacters(name.replace("+", "Plus").replace("-", "Minus")); } } diff --git a/polyapi-maven-plugin/src/main/java/io/polyapi/plugin/service/schema/PolyRuleFactory.java b/polyapi-maven-plugin/src/main/java/io/polyapi/plugin/service/schema/PolyRuleFactory.java index 2ba2ef40..de9a52ec 100644 --- a/polyapi-maven-plugin/src/main/java/io/polyapi/plugin/service/schema/PolyRuleFactory.java +++ b/polyapi-maven-plugin/src/main/java/io/polyapi/plugin/service/schema/PolyRuleFactory.java @@ -1,9 +1,5 @@ package io.polyapi.plugin.service.schema; -import com.sun.codemodel.JClassContainer; -import com.sun.codemodel.JDocComment; -import com.sun.codemodel.JDocCommentable; -import com.sun.codemodel.JType; import org.jsonschema2pojo.GenerationConfig; import org.jsonschema2pojo.Jackson2Annotator; import org.jsonschema2pojo.SchemaStore; @@ -11,6 +7,9 @@ import org.jsonschema2pojo.rules.RuleFactory; import org.jsonschema2pojo.util.NameHelper; +import com.sun.codemodel.JClassContainer; +import com.sun.codemodel.JType; + public class PolyRuleFactory extends RuleFactory { private NameHelper overwrittingNameHelper; diff --git a/polyapi-maven-plugin/src/main/java/io/polyapi/plugin/service/schema/PublicEnumRule.java b/polyapi-maven-plugin/src/main/java/io/polyapi/plugin/service/schema/PublicEnumRule.java index 6c2da4bf..ab1787f9 100644 --- a/polyapi-maven-plugin/src/main/java/io/polyapi/plugin/service/schema/PublicEnumRule.java +++ b/polyapi-maven-plugin/src/main/java/io/polyapi/plugin/service/schema/PublicEnumRule.java @@ -1,19 +1,18 @@ package io.polyapi.plugin.service.schema; -import com.fasterxml.jackson.databind.JsonNode; -import com.sun.codemodel.JClassContainer; -import com.sun.codemodel.JType; -import lombok.extern.slf4j.Slf4j; +import static java.util.Spliterator.ORDERED; +import static java.util.stream.StreamSupport.stream; + +import java.util.Spliterators; + import org.jsonschema2pojo.Schema; import org.jsonschema2pojo.rules.EnumRule; import org.jsonschema2pojo.rules.RuleFactory; -import java.util.Spliterators; - -import static java.util.Spliterator.ORDERED; -import static java.util.stream.StreamSupport.stream; +import com.fasterxml.jackson.databind.JsonNode; +import com.sun.codemodel.JClassContainer; +import com.sun.codemodel.JType; -@Slf4j public class PublicEnumRule extends EnumRule { protected PublicEnumRule(RuleFactory ruleFactory) { diff --git a/polyapi-maven-plugin/src/main/java/io/polyapi/plugin/service/visitor/CodeGenerator.java b/polyapi-maven-plugin/src/main/java/io/polyapi/plugin/service/visitor/CodeGenerator.java index 420cc49e..7859e24e 100644 --- a/polyapi-maven-plugin/src/main/java/io/polyapi/plugin/service/visitor/CodeGenerator.java +++ b/polyapi-maven-plugin/src/main/java/io/polyapi/plugin/service/visitor/CodeGenerator.java @@ -1,13 +1,11 @@ package io.polyapi.plugin.service.visitor; +import static lombok.AccessLevel.PROTECTED; + import io.polyapi.commons.api.service.file.FileService; import io.polyapi.plugin.model.generation.Generable; import lombok.Getter; import lombok.extern.slf4j.Slf4j; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import static lombok.AccessLevel.PROTECTED; @Getter(PROTECTED) @Slf4j diff --git a/polyapi-maven-plugin/src/main/java/io/polyapi/plugin/utils/StringUtils.java b/polyapi-maven-plugin/src/main/java/io/polyapi/plugin/utils/StringUtils.java index 6ea7759b..e05ce6b0 100644 --- a/polyapi-maven-plugin/src/main/java/io/polyapi/plugin/utils/StringUtils.java +++ b/polyapi-maven-plugin/src/main/java/io/polyapi/plugin/utils/StringUtils.java @@ -1,20 +1,24 @@ package io.polyapi.plugin.utils; -import org.apache.commons.text.WordUtils; - -import java.util.Optional; +import com.google.common.base.CaseFormat; import static java.util.function.Predicate.not; import static org.apache.commons.text.WordUtils.capitalize; import static org.apache.commons.text.WordUtils.uncapitalize; +import java.util.Optional; + public class StringUtils { private static final char[] DELIMITERS = new char[]{' ', '_', '-', '.'}; + private StringUtils() { + // Do nothing. + } public static String toPascalCase(String input) { + return Optional.ofNullable(input) .filter(not(String::isBlank)) - .map(value -> capitalize(input, DELIMITERS).replaceAll("_|-|\\.|\\s", "")) + .map(value -> capitalize(input, DELIMITERS).replaceAll("[\\-\\.\s]", "")) .orElse(input); } diff --git a/polyapi-maven-plugin/src/test/java/io/polyapi/plugin/model/function/PolyFunctionTest.java b/polyapi-maven-plugin/src/test/java/io/polyapi/plugin/model/function/PolyFunctionTest.java index cac74b59..576969f7 100644 --- a/polyapi-maven-plugin/src/test/java/io/polyapi/plugin/model/function/PolyFunctionTest.java +++ b/polyapi-maven-plugin/src/test/java/io/polyapi/plugin/model/function/PolyFunctionTest.java @@ -1,19 +1,18 @@ package io.polyapi.plugin.model.function; -import lombok.extern.slf4j.Slf4j; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.Arguments; -import org.junit.jupiter.params.provider.MethodSource; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import static java.util.stream.Stream.empty; +import static org.hamcrest.CoreMatchers.equalTo; +import static org.hamcrest.MatcherAssert.assertThat; import java.util.Optional; import java.util.stream.Stream; -import static java.util.stream.Stream.empty; -import static org.hamcrest.CoreMatchers.equalTo; -import static org.hamcrest.MatcherAssert.assertThat; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +import lombok.extern.slf4j.Slf4j; @Slf4j @@ -29,14 +28,14 @@ public static Stream getSignatureTestSource() throws Exception { Arguments.of("Case 6: Generic name arguments.", DEFAULT_METHOD_NAME, null, "test()"), Arguments.of("Case 7: Null name, no arguments.", null, empty(), "null()"), Arguments.of("Case 8: Null name null arguments.", null, null, "null()"), - Arguments.of("Case 9: Generic name, Null type arguments.", DEFAULT_METHOD_NAME, Stream.of(new Class[]{null}), "test(null)"), - Arguments.of("Case 10: Generic name, String argument and Null type argument.", DEFAULT_METHOD_NAME, Stream.of(new Class[]{String.class, null}), "test(java.lang.String, null)"), + Arguments.of("Case 9: Generic name, Null type arguments.", DEFAULT_METHOD_NAME, Stream.of(new Object[] {null}), "test(null)"), + Arguments.of("Case 10: Generic name, String argument and Null type argument.", DEFAULT_METHOD_NAME, Stream.of(String.class, null), "test(java.lang.String, null)"), Arguments.of("Case 11: Generic name, String argument, Null type argument and Integer argument in that order.", DEFAULT_METHOD_NAME, Stream.of(new Class[]{String.class, null, Integer.class}), "test(java.lang.String, null, java.lang.Integer)")); } @ParameterizedTest(name = "{0}") @MethodSource("getSignatureTestSource") - public void getSignatureTest(String caseName, String name, Stream> argumentTypes, String expectedResult) { + void getSignatureTest(String caseName, String name, Stream> argumentTypes, String expectedResult) { log.debug("Executing test case - {}.", caseName); log.debug("Expected result is {}.", expectedResult); var polyFunction = new PolyFunction(); diff --git a/polyapi-maven-plugin/src/test/java/io/polyapi/plugin/service/JsonSchemaParserTest.java b/polyapi-maven-plugin/src/test/java/io/polyapi/plugin/service/JsonSchemaParserTest.java index a264a1b9..df636ad5 100644 --- a/polyapi-maven-plugin/src/test/java/io/polyapi/plugin/service/JsonSchemaParserTest.java +++ b/polyapi-maven-plugin/src/test/java/io/polyapi/plugin/service/JsonSchemaParserTest.java @@ -38,8 +38,10 @@ public static Stream generateSource() { createArguments(11, "Schema that uses allof."), createArguments(12, "Schema with enum with '-' in one of the options.", "Identifier", "TestResponse"), createArguments(13, "Schema with different types that have the same enum.", "Identifier", DEFAULT_RESPONSE_NAME, "Data"), - createArguments(14, "Schema that is an Integer.")); + createArguments(14, "Schema that is an Integer."), + createArguments(15, "Schema with multiple enums with the same name and properties.", DEFAULT_RESPONSE_NAME, "DashMinusstyle", "DashMinusstyle_", "Other")); } + public static Stream getTypeSource() { return Stream.of(Arguments.of(1, "Simple recursive schema with no base type.", createClassName(DEFAULT_RESPONSE_NAME)), Arguments.of(2, "Recursive schema with base type.", createClassName(DEFAULT_RESPONSE_NAME)), @@ -80,6 +82,7 @@ public void generateTest(Integer caseNumber, String description, List ex assertThat(customTypes.size(), equalTo(expectedNames.size())); var customTypeNames = customTypes.stream().map(CustomType::getName).toList(); expectedNames.forEach(expectedName -> assertTrue(customTypeNames.contains(expectedName), format("Result should contain object with name %s. Result contains %s.", expectedName, customTypeNames))); + customTypes.forEach(customType -> assertTrue(customType.getCode().contains(format("public class %s {", customType.getName())) || customType.getCode().contains(format("public enum %s {", customType.getName())))); } @ParameterizedTest(name = "Case {0}: {1}") diff --git a/polyapi-maven-plugin/src/test/resources/io/polyapi/plugin/service/schema/cases/Case 15.schema.json b/polyapi-maven-plugin/src/test/resources/io/polyapi/plugin/service/schema/cases/Case 15.schema.json new file mode 100644 index 00000000..cd22d23d --- /dev/null +++ b/polyapi-maven-plugin/src/test/resources/io/polyapi/plugin/service/schema/cases/Case 15.schema.json @@ -0,0 +1,28 @@ +{ + "$schema": "http://json-schema.org/draft-06/schema#", + "type": "object", + "additionalProperties": false, + "properties": { + "dash-style": { + "type": "string", + "enum": [ + "SOLID" + ] + }, + "other": { + "type": "object", + "properties": { + "dash-style": { + "type": "string", + "enum": [ + "SOLID" + ] + } + } + } + }, + "required": [ + "dashStyle" + ], + "title": "Response Type" +} \ No newline at end of file