You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by da...@apache.org on 2024/03/14 18:49:04 UTC
(camel) 04/10: CAMEL-17641: Generate json metadata for pojo beans in camel-core that end users can use such as AggregationStrategy implementations. And have that information in camel-catalog for tooling assistance.
This is an automated email from the ASF dual-hosted git repository.
davsclaus pushed a commit to branch pojo-beans
in repository https://gitbox.apache.org/repos/asf/camel.git
commit fb1cee8406d4cb621e37782b3d51e1e1001772d2
Author: Claus Ibsen <cl...@gmail.com>
AuthorDate: Thu Mar 14 16:27:10 2024 +0100
CAMEL-17641: Generate json metadata for pojo beans in camel-core that end users can use such as AggregationStrategy implementations. And have that information in camel-catalog for tooling assistance.
---
.../services/org/apache/camel/bean.properties | 2 +-
.../bean/GroupedMessageAggregationStrategy.json | 15 ++++
.../camel/bean/StringAggregationStrategy.json | 16 ++++
.../GroupedMessageAggregationStrategy.java | 5 ++
.../aggregate/StringAggregationStrategy.java | 21 ++++++
.../packaging/EndpointSchemaGeneratorMojo.java | 82 +--------------------
.../maven/packaging/GeneratePojoBeanMojo.java | 85 +++++++++++++++++++---
.../apache/camel/maven/packaging/MojoHelper.java | 76 +++++++++++++++++++
8 files changed, 210 insertions(+), 92 deletions(-)
diff --git a/core/camel-core-processor/src/generated/resources/META-INF/services/org/apache/camel/bean.properties b/core/camel-core-processor/src/generated/resources/META-INF/services/org/apache/camel/bean.properties
index 348c3b28c96..88fd1692084 100644
--- a/core/camel-core-processor/src/generated/resources/META-INF/services/org/apache/camel/bean.properties
+++ b/core/camel-core-processor/src/generated/resources/META-INF/services/org/apache/camel/bean.properties
@@ -1,5 +1,5 @@
# Generated by camel build tools - do NOT edit this file!
-bean=UseLatestAggregationStrategy UseOriginalAggregationStrategy
+bean=GroupedMessageAggregationStrategy StringAggregationStrategy UseLatestAggregationStrategy UseOriginalAggregationStrategy
groupId=org.apache.camel
artifactId=camel-core-processor
version=4.5.0-SNAPSHOT
diff --git a/core/camel-core-processor/src/generated/resources/META-INF/services/org/apache/camel/bean/GroupedMessageAggregationStrategy.json b/core/camel-core-processor/src/generated/resources/META-INF/services/org/apache/camel/bean/GroupedMessageAggregationStrategy.json
new file mode 100644
index 00000000000..a03cad939d9
--- /dev/null
+++ b/core/camel-core-processor/src/generated/resources/META-INF/services/org/apache/camel/bean/GroupedMessageAggregationStrategy.json
@@ -0,0 +1,15 @@
+{
+ "bean": {
+ "kind": "bean",
+ "name": "GroupedMessageAggregationStrategy",
+ "javaType": "org.apache.camel.processor.aggregate.GroupedMessageAggregationStrategy",
+ "interfaceType": "org.apache.camel.AggregationStrategy",
+ "title": "Grouped Message Aggregation Strategy",
+ "description": "Aggregate all Message into a single combined Exchange holding all the aggregated messages in a List of Message as the message body. This aggregation strategy can be used in combination with Splitter to batch messages.",
+ "deprecated": false,
+ "groupId": "org.apache.camel",
+ "artifactId": "camel-core-processor",
+ "version": "4.5.0-SNAPSHOT"
+ }
+}
+
diff --git a/core/camel-core-processor/src/generated/resources/META-INF/services/org/apache/camel/bean/StringAggregationStrategy.json b/core/camel-core-processor/src/generated/resources/META-INF/services/org/apache/camel/bean/StringAggregationStrategy.json
new file mode 100644
index 00000000000..1702da816d7
--- /dev/null
+++ b/core/camel-core-processor/src/generated/resources/META-INF/services/org/apache/camel/bean/StringAggregationStrategy.json
@@ -0,0 +1,16 @@
+{
+ "bean": {
+ "kind": "bean",
+ "name": "StringAggregationStrategy",
+ "javaType": "org.apache.camel.processor.aggregate.StringAggregationStrategy",
+ "interfaceType": "org.apache.camel.AggregationStrategy",
+ "title": "String Aggregation Strategy",
+ "description": "Aggregate result of pick expression into a single combined Exchange holding all the aggregated bodies in a String as the message body. This aggregation strategy can used in combination with Splitter to batch messages",
+ "deprecated": false,
+ "groupId": "org.apache.camel",
+ "artifactId": "camel-core-processor",
+ "version": "4.5.0-SNAPSHOT",
+ "options": { "delimiter": { "index": 0, "kind": "property", "displayName": "Delimiter", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Delimiter used for joining strings together." } }
+ }
+}
+
diff --git a/core/camel-core-processor/src/main/java/org/apache/camel/processor/aggregate/GroupedMessageAggregationStrategy.java b/core/camel-core-processor/src/main/java/org/apache/camel/processor/aggregate/GroupedMessageAggregationStrategy.java
index ef47d5d0a02..aca104407c3 100644
--- a/core/camel-core-processor/src/main/java/org/apache/camel/processor/aggregate/GroupedMessageAggregationStrategy.java
+++ b/core/camel-core-processor/src/main/java/org/apache/camel/processor/aggregate/GroupedMessageAggregationStrategy.java
@@ -20,6 +20,7 @@ import java.util.List;
import org.apache.camel.Exchange;
import org.apache.camel.Message;
+import org.apache.camel.spi.Metadata;
import org.apache.camel.support.DefaultExchange;
/**
@@ -29,6 +30,10 @@ import org.apache.camel.support.DefaultExchange;
* This aggregation strategy can be used in combination with {@link org.apache.camel.processor.Splitter} to batch
* messages
*/
+@Metadata(label = "bean",
+ description = "Aggregate all Message into a single combined Exchange holding all the aggregated messages in a List"
+ + " of Message as the message body. This aggregation strategy can be used in combination with"
+ + " Splitter to batch messages.")
public class GroupedMessageAggregationStrategy extends AbstractListAggregationStrategy<Message> {
@Override
diff --git a/core/camel-core-processor/src/main/java/org/apache/camel/processor/aggregate/StringAggregationStrategy.java b/core/camel-core-processor/src/main/java/org/apache/camel/processor/aggregate/StringAggregationStrategy.java
index ed08e6a0a8b..5e8694fd923 100644
--- a/core/camel-core-processor/src/main/java/org/apache/camel/processor/aggregate/StringAggregationStrategy.java
+++ b/core/camel-core-processor/src/main/java/org/apache/camel/processor/aggregate/StringAggregationStrategy.java
@@ -20,6 +20,7 @@ import org.apache.camel.AggregationStrategy;
import org.apache.camel.Exchange;
import org.apache.camel.ExchangePropertyKey;
import org.apache.camel.Expression;
+import org.apache.camel.spi.Metadata;
import org.apache.camel.support.builder.ExpressionBuilder;
/**
@@ -28,11 +29,31 @@ import org.apache.camel.support.builder.ExpressionBuilder;
*
* This aggregation strategy can used in combination with {@link org.apache.camel.processor.Splitter} to batch messages
*/
+@Metadata(label = "bean",
+ description = "Aggregate result of pick expression into a single combined Exchange holding all the aggregated bodies in a"
+ + " String as the message body. This aggregation strategy can used in combination with Splitter to batch messages")
public class StringAggregationStrategy implements AggregationStrategy {
+ @Metadata(description = "Delimiter used for joining strings together.")
private String delimiter = "";
private Expression pickExpression = ExpressionBuilder.bodyExpression();
+ public String getDelimiter() {
+ return delimiter;
+ }
+
+ public void setDelimiter(String delimiter) {
+ this.delimiter = delimiter;
+ }
+
+ public Expression getPickExpression() {
+ return pickExpression;
+ }
+
+ public void setPickExpression(Expression pickExpression) {
+ this.pickExpression = pickExpression;
+ }
+
/**
* Set delimiter used for joining aggregated String
*
diff --git a/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/EndpointSchemaGeneratorMojo.java b/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/EndpointSchemaGeneratorMojo.java
index 6f5328c0929..a3a47d330b3 100644
--- a/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/EndpointSchemaGeneratorMojo.java
+++ b/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/EndpointSchemaGeneratorMojo.java
@@ -27,8 +27,6 @@ import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.Type;
-import java.net.URI;
-import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
@@ -36,7 +34,6 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
-import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
@@ -1077,7 +1074,7 @@ public class EndpointSchemaGeneratorMojo extends AbstractGeneratorMojo {
option.setKind("property");
option.setName(name);
option.setDisplayName(displayName);
- option.setType(getType(fieldTypeName, false, isDuration));
+ option.setType(MojoHelper.getType(fieldTypeName, false, isDuration));
option.setJavaType(fieldTypeName);
option.setRequired(required);
option.setDefaultValue(defaultValue);
@@ -1364,7 +1361,7 @@ public class EndpointSchemaGeneratorMojo extends AbstractGeneratorMojo {
}
option.setName(name);
option.setDisplayName(displayName);
- option.setType(getType(fieldTypeName, false, isDuration));
+ option.setType(MojoHelper.getType(fieldTypeName, false, isDuration));
option.setJavaType(fieldTypeName);
option.setRequired(required);
option.setDefaultValue(defaultValue);
@@ -1553,7 +1550,7 @@ public class EndpointSchemaGeneratorMojo extends AbstractGeneratorMojo {
option.setName(name);
option.setKind("path");
option.setDisplayName(displayName);
- option.setType(getType(fieldTypeName, false, isDuration));
+ option.setType(MojoHelper.getType(fieldTypeName, false, isDuration));
option.setJavaType(fieldTypeName);
option.setRequired(required);
option.setDefaultValue(defaultValue);
@@ -1875,79 +1872,6 @@ public class EndpointSchemaGeneratorMojo extends AbstractGeneratorMojo {
return fieldTypeName;
}
- /**
- * Gets the JSON schema type.
- *
- * @param type the java type
- * @return the json schema type, is never null, but returns <tt>object</tt> as the generic type
- */
- public static String getType(String type, boolean enumType, boolean isDuration) {
- if (enumType) {
- return "enum";
- } else if (isDuration) {
- return "duration";
- } else if (type == null) {
- // return generic type for unknown type
- return "object";
- } else if (type.equals(URI.class.getName()) || type.equals(URL.class.getName())) {
- return "string";
- } else if (type.equals(File.class.getName())) {
- return "string";
- } else if (type.equals(Date.class.getName())) {
- return "string";
- } else if (type.startsWith("java.lang.Class")) {
- return "string";
- } else if (type.startsWith("java.util.List") || type.startsWith("java.util.Collection")) {
- return "array";
- }
-
- String primitive = getPrimitiveType(type);
- if (primitive != null) {
- return primitive;
- }
-
- return "object";
- }
-
- /**
- * Gets the JSON schema primitive type.
- *
- * @param name the java type
- * @return the json schema primitive type, or <tt>null</tt> if not a primitive
- */
- public static String getPrimitiveType(String name) {
- // special for byte[] or Object[] as its common to use
- if ("java.lang.byte[]".equals(name) || "byte[]".equals(name)) {
- return "string";
- } else if ("java.lang.Byte[]".equals(name) || "Byte[]".equals(name)) {
- return "array";
- } else if ("java.lang.Object[]".equals(name) || "Object[]".equals(name)) {
- return "array";
- } else if ("java.lang.String[]".equals(name) || "String[]".equals(name)) {
- return "array";
- } else if ("java.lang.Character".equals(name) || "Character".equals(name) || "char".equals(name)) {
- return "string";
- } else if ("java.lang.String".equals(name) || "String".equals(name)) {
- return "string";
- } else if ("java.lang.Boolean".equals(name) || "Boolean".equals(name) || "boolean".equals(name)) {
- return "boolean";
- } else if ("java.lang.Integer".equals(name) || "Integer".equals(name) || "int".equals(name)) {
- return "integer";
- } else if ("java.lang.Long".equals(name) || "Long".equals(name) || "long".equals(name)) {
- return "integer";
- } else if ("java.lang.Short".equals(name) || "Short".equals(name) || "short".equals(name)) {
- return "integer";
- } else if ("java.lang.Byte".equals(name) || "Byte".equals(name) || "byte".equals(name)) {
- return "integer";
- } else if ("java.lang.Float".equals(name) || "Float".equals(name) || "float".equals(name)) {
- return "number";
- } else if ("java.lang.Double".equals(name) || "Double".equals(name) || "double".equals(name)) {
- return "number";
- }
-
- return null;
- }
-
/**
* Gets the default value accordingly to its type
*
diff --git a/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/GeneratePojoBeanMojo.java b/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/GeneratePojoBeanMojo.java
index 438b0de9744..4787b307841 100644
--- a/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/GeneratePojoBeanMojo.java
+++ b/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/GeneratePojoBeanMojo.java
@@ -21,12 +21,14 @@ import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.StringJoiner;
+import java.util.stream.Stream;
import org.apache.camel.maven.packaging.generics.PackagePluginUtils;
+import org.apache.camel.tooling.model.BaseOptionModel;
+import org.apache.camel.tooling.model.JsonMapper;
import org.apache.camel.tooling.util.PackageHelper;
import org.apache.camel.tooling.util.Strings;
import org.apache.camel.util.json.JsonObject;
-import org.apache.camel.util.json.Jsoner;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;
import org.apache.maven.plugins.annotations.LifecyclePhase;
@@ -34,10 +36,13 @@ import org.apache.maven.plugins.annotations.Mojo;
import org.apache.maven.plugins.annotations.Parameter;
import org.apache.maven.plugins.annotations.ResolutionScope;
import org.jboss.jandex.AnnotationInstance;
+import org.jboss.jandex.ClassInfo;
import org.jboss.jandex.DotName;
+import org.jboss.jandex.FieldInfo;
import org.jboss.jandex.Index;
import static org.apache.camel.maven.packaging.MojoHelper.annotationValue;
+import static org.apache.camel.maven.packaging.MojoHelper.getType;
/**
* Factory for generating code for Camel pojo beans that are intended for end user to use with Camel EIPs and
@@ -66,6 +71,7 @@ public class GeneratePojoBeanMojo extends AbstractGeneratorMojo {
private String interfaceName;
private String description;
private boolean deprecated;
+ private final List<BeanPojoOptionModel> options = new ArrayList<>();
public String getName() {
return name;
@@ -114,6 +120,18 @@ public class GeneratePojoBeanMojo extends AbstractGeneratorMojo {
public void setDeprecated(boolean deprecated) {
this.deprecated = deprecated;
}
+
+ public void addOption(BeanPojoOptionModel option) {
+ this.options.add(option);
+ }
+
+ public List<BeanPojoOptionModel> getOptions() {
+ return options;
+ }
+ }
+
+ private static class BeanPojoOptionModel extends BaseOptionModel {
+
}
public GeneratePojoBeanMojo() {
@@ -143,25 +161,47 @@ public class GeneratePojoBeanMojo extends AbstractGeneratorMojo {
String label = annotationValue(a, "label");
if ("bean".equals(label)) {
BeanPojoModel model = new BeanPojoModel();
- model.setName(a.target().asClass().simpleName());
- boolean deprecated = a.target().asClass().hasAnnotation(Deprecated.class);
+ ClassInfo ci = a.target().asClass();
+ model.setName(ci.simpleName());
+ boolean deprecated = ci.hasAnnotation(Deprecated.class);
String title = annotationValue(a, "title");
if (title == null) {
title = Strings.camelCaseToDash(model.getName());
title = Strings.camelDashToTitle(title);
}
model.setTitle(title);
- model.setClassName(a.target().asClass().name().toString());
+ model.setClassName(ci.name().toString());
model.setDeprecated(deprecated);
model.setDescription(annotationValue(a, "description"));
- for (DotName dn : a.target().asClass().interfaceNames()) {
- if (dn.packagePrefix().startsWith("org.apache.camel")) {
- model.setInterfaceName(dn.toString());
- break;
+ model.setInterfaceName(interfaceName(index, ci));
+
+ // find all fields with @Metadata as options
+ for (FieldInfo fi : ci.fields()) {
+ AnnotationInstance ai = fi.annotation(METADATA);
+ if (ai != null) {
+ BeanPojoOptionModel o = new BeanPojoOptionModel();
+ o.setKind("property");
+ o.setName(fi.name());
+ o.setLabel(annotationValue(ai, "label"));
+ o.setDefaultValue(annotationValue(ai, "defaultValue"));
+ o.setRequired("true".equals(annotationValue(ai, "required")));
+ String displayName = annotationValue(ai, "title");
+ if (displayName == null) {
+ displayName = Strings.asTitle(o.getName());
+ }
+ o.setDisplayName(displayName);
+ o.setDeprecated(fi.hasAnnotation(Deprecated.class));
+ o.setJavaType(fi.type().name().toString());
+ o.setType(getType(o.getJavaType(), false, false));
+ o.setDescription(annotationValue(ai, "description"));
+ String enums = annotationValue(ai, "enums");
+ if (enums != null) {
+ String[] values = enums.split(",");
+ o.setEnums(Stream.of(values).map(String::trim).toList());
+ }
+ model.addOption(o);
}
}
-
- // TODO: getter/setter for options ala EIP/components
models.add(model);
}
});
@@ -173,8 +213,7 @@ public class GeneratePojoBeanMojo extends AbstractGeneratorMojo {
for (var model : models) {
names.add(model.getName());
JsonObject jo = asJsonObject(model);
- String json = jo.toJson();
- json = Jsoner.prettyPrint(json, 2);
+ String json = JsonMapper.serialize(jo);
String fn = sanitizeFileName(model.getName()) + PackageHelper.JSON_SUFIX;
boolean updated = updateResource(resourcesOutputDir.toPath(),
"META-INF/services/org/apache/camel/bean/" + fn,
@@ -197,6 +236,22 @@ public class GeneratePojoBeanMojo extends AbstractGeneratorMojo {
}
}
+ private static String interfaceName(Index index, ClassInfo target) {
+ for (DotName dn : target.interfaceNames()) {
+ if (dn.packagePrefix().startsWith("org.apache.camel")) {
+ return dn.toString();
+ }
+ }
+ if (target.superName() != null) {
+ DotName dn = target.superName();
+ ClassInfo ci = index.getClassByName(dn);
+ if (ci != null) {
+ return interfaceName(index, ci);
+ }
+ }
+ return null;
+ }
+
private JsonObject asJsonObject(BeanPojoModel model) {
JsonObject jo = new JsonObject();
// we need to know the maven GAV also
@@ -214,6 +269,12 @@ public class GeneratePojoBeanMojo extends AbstractGeneratorMojo {
jo.put("groupId", project.getGroupId());
jo.put("artifactId", project.getArtifactId());
jo.put("version", project.getVersion());
+
+ if (!model.getOptions().isEmpty()) {
+ JsonObject options = JsonMapper.asJsonObject(model.getOptions());
+ jo.put("options", options);
+ }
+
JsonObject root = new JsonObject();
root.put("bean", jo);
return root;
diff --git a/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/MojoHelper.java b/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/MojoHelper.java
index 350579b5fc6..95f5a1de142 100644
--- a/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/MojoHelper.java
+++ b/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/MojoHelper.java
@@ -16,9 +16,13 @@
*/
package org.apache.camel.maven.packaging;
+import java.io.File;
+import java.net.URI;
+import java.net.URL;
import java.nio.file.Path;
import java.util.Arrays;
import java.util.Collections;
+import java.util.Date;
import java.util.List;
import org.jboss.jandex.AnnotationInstance;
@@ -132,4 +136,76 @@ public final class MojoHelper {
return s == null || s.isBlank() ? null : s;
}
+ /**
+ * Gets the JSON schema type.
+ *
+ * @param type the java type
+ * @return the json schema type, is never null, but returns <tt>object</tt> as the generic type
+ */
+ public static String getType(String type, boolean enumType, boolean isDuration) {
+ if (enumType) {
+ return "enum";
+ } else if (isDuration) {
+ return "duration";
+ } else if (type == null) {
+ // return generic type for unknown type
+ return "object";
+ } else if (type.equals(URI.class.getName()) || type.equals(URL.class.getName())) {
+ return "string";
+ } else if (type.equals(File.class.getName())) {
+ return "string";
+ } else if (type.equals(Date.class.getName())) {
+ return "string";
+ } else if (type.startsWith("java.lang.Class")) {
+ return "string";
+ } else if (type.startsWith("java.util.List") || type.startsWith("java.util.Collection")) {
+ return "array";
+ }
+
+ String primitive = getPrimitiveType(type);
+ if (primitive != null) {
+ return primitive;
+ }
+
+ return "object";
+ }
+
+ /**
+ * Gets the JSON schema primitive type.
+ *
+ * @param name the java type
+ * @return the json schema primitive type, or <tt>null</tt> if not a primitive
+ */
+ public static String getPrimitiveType(String name) {
+ // special for byte[] or Object[] as its common to use
+ if ("java.lang.byte[]".equals(name) || "byte[]".equals(name)) {
+ return "string";
+ } else if ("java.lang.Byte[]".equals(name) || "Byte[]".equals(name)) {
+ return "array";
+ } else if ("java.lang.Object[]".equals(name) || "Object[]".equals(name)) {
+ return "array";
+ } else if ("java.lang.String[]".equals(name) || "String[]".equals(name)) {
+ return "array";
+ } else if ("java.lang.Character".equals(name) || "Character".equals(name) || "char".equals(name)) {
+ return "string";
+ } else if ("java.lang.String".equals(name) || "String".equals(name)) {
+ return "string";
+ } else if ("java.lang.Boolean".equals(name) || "Boolean".equals(name) || "boolean".equals(name)) {
+ return "boolean";
+ } else if ("java.lang.Integer".equals(name) || "Integer".equals(name) || "int".equals(name)) {
+ return "integer";
+ } else if ("java.lang.Long".equals(name) || "Long".equals(name) || "long".equals(name)) {
+ return "integer";
+ } else if ("java.lang.Short".equals(name) || "Short".equals(name) || "short".equals(name)) {
+ return "integer";
+ } else if ("java.lang.Byte".equals(name) || "Byte".equals(name) || "byte".equals(name)) {
+ return "integer";
+ } else if ("java.lang.Float".equals(name) || "Float".equals(name) || "float".equals(name)) {
+ return "number";
+ } else if ("java.lang.Double".equals(name) || "Double".equals(name) || "double".equals(name)) {
+ return "number";
+ }
+
+ return null;
+ }
}