Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 20 additions & 4 deletions api/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@
<name>Serverless Workflow :: API</name>
<packaging>jar</packaging>
<description>Java SDK for Serverless Workflow Specification</description>
<properties>
<version.build-helper-maven-plugin>3.6.1</version.build-helper-maven-plugin>
</properties>

<dependencies>
<dependency>
Expand Down Expand Up @@ -75,9 +78,8 @@
<scope>test</scope>
</dependency>
</dependencies>
<build>
<build>
<plugins>
Comment thread
fjtirado marked this conversation as resolved.

<plugin>
<groupId>io.serverlessworkflow</groupId>
<artifactId>serverless-workflow-jackson-generator</artifactId>
Expand All @@ -100,7 +102,7 @@
<!-- a hint for IDE's to add the java sources to the classpath -->
<groupId>org.codehaus.mojo</groupId>
<artifactId>build-helper-maven-plugin</artifactId>
<version>3.6.1</version>
<version>${version.build-helper-maven-plugin}</version>
<executions>
<execution>
<id>add-mixin</id>
Expand All @@ -114,8 +116,22 @@
</sources>
</configuration>
</execution>
<execution>
<id>add-resource</id>
<phase>generate-sources</phase>
<goals>
<goal>add-resource</goal>
</goals>
<configuration>
<resources>
<resource>
<directory>${project.build.directory}/generated-resources</directory>
</resource>
</resources>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
/*
* Copyright 2020-Present The Serverless Workflow Specification Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.serverlessworkflow.generator.graalvm;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.sun.codemodel.JDefinedClass;
import java.io.IOException;
import java.io.Writer;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.stream.Stream;

public class ReflectNativeFileHandler {

private final String groupId;
private final String artifactId;
private final ArrayNode rootObject;
private static final ObjectMapper objectMapper = new ObjectMapper();

public ReflectNativeFileHandler(String groupId, String artifactId) {
this.groupId = groupId;
this.artifactId = artifactId;
this.rootObject = objectMapper.createArrayNode();
}

public ReflectNativeFileHandler addClasses(Stream<String> classNames) {
classNames.forEach(this::addClass);
return this;
}

public ReflectNativeFileHandler addClasses(Iterable<String> classNames) {
classNames.forEach(this::addClass);
return this;
}

public ReflectNativeFileHandler addClass(String refClassName) {
rootObject.add(buildObjectFromClass(refClassName));
return this;
}

public ReflectNativeFileHandler addClass(JDefinedClass definedClass) {
addClass(definedClass.fullName());
return this;
}

private static JsonNode buildObjectFromClass(String refClassName) {
return objectMapper
.createObjectNode()
.put("name", refClassName)
.put("queryAllPublicConstructors", true)
.put("queryAllDeclaredConstructors", true)
.put("queryAllPublicMethods", true)
.put("queryAllDeclaredMethods", true)
.put("allPublicConstructors", true)
.put("allDeclaredConstructors", true)
.put("allPublicMethods", true)
.put("allDeclaredMethods", true)
.put("allPublicFields", true)
.put("allDeclaredFields", true)
.put("allPublicClasses", true)
.put("allDeclaredClasses", true);
}

public void generate(Path rootPath) throws IOException {
try (Writer out =
Files.newBufferedWriter(
Files.createDirectories(
rootPath
.resolve("META-INF")
.resolve("native-image")
.resolve(groupId)
.resolve(artifactId))
.resolve("reflect-config.json"))) {
objectMapper.writeValue(out, rootObject);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ public static void fillDeserializer(
private static JDefinedClass createClass(
JPackage jPackage, JClass relatedClass, Class<?> serializerClass, String suffix)
throws JClassAlreadyExistsException {
JDefinedClass definedClass = jPackage._class(JMod.NONE, relatedClass.name() + suffix);
JDefinedClass definedClass = jPackage._class(JMod.PUBLIC, relatedClass.name() + suffix);
definedClass._extends(definedClass.owner().ref(serializerClass).narrow(relatedClass));
return definedClass;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@
import io.serverlessworkflow.annotations.Item;
import io.serverlessworkflow.annotations.ItemKey;
import io.serverlessworkflow.annotations.ItemValue;
import io.serverlessworkflow.generator.graalvm.ReflectNativeFileHandler;
import java.io.File;
import java.io.IOException;
import java.io.PrintStream;
Expand Down Expand Up @@ -78,6 +79,17 @@ public class JacksonMixInPojo extends AbstractMojo {
defaultValue = "${project.build.directory}/generated-sources/jacksonmixinpojo")
private File outputDirectory;

@Parameter(defaultValue = "${project.groupId}", readonly = true, required = true)
private String groupId;

@Parameter(defaultValue = "${project.artifactId}", readonly = true, required = true)
private String artifactId;

@Parameter(
property = "jacksonmixinpojo.outputResources",
defaultValue = "${project.build.directory}/generated-resources")
private File outputResources;

@Parameter(property = "jacksonmixinpojo.srcPackage")
private String srcPackage;

Expand All @@ -90,6 +102,7 @@ public class JacksonMixInPojo extends AbstractMojo {
private JCodeModel codeModel;
private JPackage rootPackage;
private JMethod setupMethod;
private ReflectNativeFileHandler nativeHandler;

@FunctionalInterface
interface AnnotationProcessor {
Expand All @@ -99,20 +112,21 @@ void accept(ClassInfo classInfo, JDefinedClass definedClass)

@Override
public void execute() throws MojoExecutionException, MojoFailureException {

try (ScanResult result =
new ClassGraph()
.enableAnnotationInfo()
.enableMethodInfo()
.acceptPackages(srcPackage)
.scan()) {
codeModel = new JCodeModel();
nativeHandler = new ReflectNativeFileHandler(groupId, artifactId);
rootPackage = codeModel._package(targetPackage);
setupMethod =
rootPackage
._class("JacksonMixInModule")
._extends(SimpleModule.class)
.method(JMod.PUBLIC, codeModel.VOID, SETUP_METHOD);
nativeHandler.addClasses(result.getAllClasses().stream().map(c -> c.getName()));
processAnnotatedClasses(result, ExclusiveUnion.class, this::buildExclusiveUnionMixIn);
Comment thread
fjtirado marked this conversation as resolved.
processAnnotatedClasses(result, InclusiveUnion.class, this::buildInclusiveUnionMixIn);
processAnnotatedClasses(result, AdditionalProperties.class, this::buildAdditionalPropsMixIn);
Expand All @@ -124,6 +138,8 @@ public void execute() throws MojoExecutionException, MojoFailureException {
.arg(setupMethod.param(SetupContext.class, "context"));
Files.createDirectories(outputDirectory.toPath());
codeModel.build(outputDirectory, (PrintStream) null);

nativeHandler.generate(outputResources.toPath());
} catch (JClassAlreadyExistsException | IOException e) {
getLog().error(e);
}
Expand All @@ -149,7 +165,8 @@ private void processAnnotatedClasses(

private JExpression processAnnotatedClass(ClassInfo classInfo, AnnotationProcessor processor)
throws JClassAlreadyExistsException {
JDefinedClass result = createMixInClass(classInfo);
JDefinedClass result = rootPackage._class(JMod.ABSTRACT, classInfo.getSimpleName() + "MixIn");
nativeHandler.addClass(result);
processor.accept(classInfo, result);
return JExpr.dotclass(result);
}
Expand Down Expand Up @@ -179,31 +196,28 @@ private void buildItemMixIn(ClassInfo classInfo, JDefinedClass mixClass)
classInfo.getMethodInfo().filter(m -> m.hasAnnotation(ItemKey.class)).get(0);
MethodInfo valueMethod =
classInfo.getMethodInfo().filter(m -> m.hasAnnotation(ItemValue.class)).get(0);
mixClass
.annotate(JsonSerialize.class)
.param(
"using",
GeneratorUtils.generateSerializer(
rootPackage, relClass, keyMethod.getName(), valueMethod.getName()));
mixClass
.annotate(JsonDeserialize.class)
.param(
"using",
GeneratorUtils.generateDeserializer(rootPackage, relClass, getReturnType(valueMethod)));
JDefinedClass serializerClass =
GeneratorUtils.generateSerializer(
rootPackage, relClass, keyMethod.getName(), valueMethod.getName());
nativeHandler.addClass(serializerClass);
mixClass.annotate(JsonSerialize.class).param("using", serializerClass);
JDefinedClass deserializerClass =
GeneratorUtils.generateDeserializer(rootPackage, relClass, getReturnType(valueMethod));
nativeHandler.addClass(deserializerClass);
mixClass.annotate(JsonDeserialize.class).param("using", deserializerClass);
}

private void buildExclusiveUnionMixIn(ClassInfo unionClassInfo, JDefinedClass unionMixClass)
throws JClassAlreadyExistsException {
JClass unionClass = codeModel.ref(unionClassInfo.getName());
unionMixClass
.annotate(JsonSerialize.class)
.param("using", GeneratorUtils.generateSerializer(rootPackage, unionClass));
unionMixClass
.annotate(JsonDeserialize.class)
.param(
"using",
GeneratorUtils.generateDeserializer(
rootPackage, unionClass, getUnionClasses(ExclusiveUnion.class, unionClassInfo)));
JDefinedClass serializerClass = GeneratorUtils.generateSerializer(rootPackage, unionClass);
unionMixClass.annotate(JsonSerialize.class).param("using", serializerClass);
nativeHandler.addClass(serializerClass);
JDefinedClass deserializerClass =
GeneratorUtils.generateDeserializer(
rootPackage, unionClass, getUnionClasses(ExclusiveUnion.class, unionClassInfo));
unionMixClass.annotate(JsonDeserialize.class).param("using", deserializerClass);
nativeHandler.addClass(deserializerClass);
}

private void buildInclusiveUnionMixIn(ClassInfo unionClassInfo, JDefinedClass unionMixClass)
Expand All @@ -229,10 +243,6 @@ private void buildEnumMixIn(ClassInfo classInfo, JDefinedClass mixClass)
staticMethod.body()._return(JExpr._null());
}

private JDefinedClass createMixInClass(ClassInfo classInfo) throws JClassAlreadyExistsException {
return rootPackage._class(JMod.ABSTRACT, classInfo.getSimpleName() + "MixIn");
}

private Collection<JClass> getUnionClasses(
Class<? extends Annotation> annotation, ClassInfo unionClassInfo) {
AnnotationInfo info = unionClassInfo.getAnnotationInfoRepeatable(annotation).get(0);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[
{"name":"io.serverlessworkflow.impl.WorkflowError","queryAllPublicConstructors":true,"queryAllDeclaredConstructors":true,"queryAllPublicMethods":true,"queryAllDeclaredMethods":true,"allPublicConstructors":true,"allDeclaredConstructors":true,"allPublicMethods":true,"allDeclaredMethods":true,"allPublicFields":true,"allDeclaredFields":true,"allPublicClasses":true,"allDeclaredClasses":true}
]
Comment thread
fjtirado marked this conversation as resolved.
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
[
{"name":"io.serverlessworkflow.impl.executors.openapi.UnifiedOpenAPI","queryAllPublicConstructors":true,"queryAllDeclaredConstructors":true,"queryAllPublicMethods":true,"queryAllDeclaredMethods":true,"allPublicConstructors":true,"allDeclaredConstructors":true,"allPublicMethods":true,"allDeclaredMethods":true,"allPublicFields":true,"allDeclaredFields":true,"allPublicClasses":true,"allDeclaredClasses":true},
{"name":"io.serverlessworkflow.impl.executors.openapi.UnifiedOpenAPI$Components","queryAllPublicConstructors":true,"queryAllDeclaredConstructors":true,"queryAllPublicMethods":true,"queryAllDeclaredMethods":true,"allPublicConstructors":true,"allDeclaredConstructors":true,"allPublicMethods":true,"allDeclaredMethods":true,"allPublicFields":true,"allDeclaredFields":true,"allPublicClasses":true,"allDeclaredClasses":true},
{"name":"io.serverlessworkflow.impl.executors.openapi.UnifiedOpenAPI$Content","queryAllPublicConstructors":true,"queryAllDeclaredConstructors":true,"queryAllPublicMethods":true,"queryAllDeclaredMethods":true,"allPublicConstructors":true,"allDeclaredConstructors":true,"allPublicMethods":true,"allDeclaredMethods":true,"allPublicFields":true,"allDeclaredFields":true,"allPublicClasses":true,"allDeclaredClasses":true},
{"name":"io.serverlessworkflow.impl.executors.openapi.UnifiedOpenAPI$HttpOperation","queryAllPublicConstructors":true,"queryAllDeclaredConstructors":true,"queryAllPublicMethods":true,"queryAllDeclaredMethods":true,"allPublicConstructors":true,"allDeclaredConstructors":true,"allPublicMethods":true,"allDeclaredMethods":true,"allPublicFields":true,"allDeclaredFields":true,"allPublicClasses":true,"allDeclaredClasses":true},
{"name":"io.serverlessworkflow.impl.executors.openapi.UnifiedOpenAPI$MediaType","queryAllPublicConstructors":true,"queryAllDeclaredConstructors":true,"queryAllPublicMethods":true,"queryAllDeclaredMethods":true,"allPublicConstructors":true,"allDeclaredConstructors":true,"allPublicMethods":true,"allDeclaredMethods":true,"allPublicFields":true,"allDeclaredFields":true,"allPublicClasses":true,"allDeclaredClasses":true},
{"name":"io.serverlessworkflow.impl.executors.openapi.UnifiedOpenAPI$Operation","queryAllPublicConstructors":true,"queryAllDeclaredConstructors":true,"queryAllPublicMethods":true,"queryAllDeclaredMethods":true,"allPublicConstructors":true,"allDeclaredConstructors":true,"allPublicMethods":true,"allDeclaredMethods":true,"allPublicFields":true,"allDeclaredFields":true,"allPublicClasses":true,"allDeclaredClasses":true},
{"name":"io.serverlessworkflow.impl.executors.openapi.UnifiedOpenAPI$Parameter","queryAllPublicConstructors":true,"queryAllDeclaredConstructors":true,"queryAllPublicMethods":true,"queryAllDeclaredMethods":true,"allPublicConstructors":true,"allDeclaredConstructors":true,"allPublicMethods":true,"allDeclaredMethods":true,"allPublicFields":true,"allDeclaredFields":true,"allPublicClasses":true,"allDeclaredClasses":true},
{"name":"io.serverlessworkflow.impl.executors.openapi.UnifiedOpenAPI$PathItem","queryAllPublicConstructors":true,"queryAllDeclaredConstructors":true,"queryAllPublicMethods":true,"queryAllDeclaredMethods":true,"allPublicConstructors":true,"allDeclaredConstructors":true,"allPublicMethods":true,"allDeclaredMethods":true,"allPublicFields":true,"allDeclaredFields":true,"allPublicClasses":true,"allDeclaredClasses":true},
{"name":"io.serverlessworkflow.impl.executors.openapi.UnifiedOpenAPI$RequestBody","queryAllPublicConstructors":true,"queryAllDeclaredConstructors":true,"queryAllPublicMethods":true,"queryAllDeclaredMethods":true,"allPublicConstructors":true,"allDeclaredConstructors":true,"allPublicMethods":true,"allDeclaredMethods":true,"allPublicFields":true,"allDeclaredFields":true,"allPublicClasses":true,"allDeclaredClasses":true},
{"name":"io.serverlessworkflow.impl.executors.openapi.UnifiedOpenAPI$Schema","queryAllPublicConstructors":true,"queryAllDeclaredConstructors":true,"queryAllPublicMethods":true,"queryAllDeclaredMethods":true,"allPublicConstructors":true,"allDeclaredConstructors":true,"allPublicMethods":true,"allDeclaredMethods":true,"allPublicFields":true,"allDeclaredFields":true,"allPublicClasses":true,"allDeclaredClasses":true},
{"name":"io.serverlessworkflow.impl.executors.openapi.UnifiedOpenAPI$Server","queryAllPublicConstructors":true,"queryAllDeclaredConstructors":true,"queryAllPublicMethods":true,"queryAllDeclaredMethods":true,"allPublicConstructors":true,"allDeclaredConstructors":true,"allPublicMethods":true,"allDeclaredMethods":true,"allPublicFields":true,"allDeclaredFields":true,"allPublicClasses":true,"allDeclaredClasses":true},
{"name":"io.serverlessworkflow.impl.executors.openapi.UnifiedOpenAPI$SwaggerVersion","queryAllPublicConstructors":true,"queryAllDeclaredConstructors":true,"queryAllPublicMethods":true,"queryAllDeclaredMethods":true,"allPublicConstructors":true,"allDeclaredConstructors":true,"allPublicMethods":true,"allDeclaredMethods":true,"allPublicFields":true,"allDeclaredFields":true,"allPublicClasses":true,"allDeclaredClasses":true}
]
Loading