You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by nf...@apache.org on 2022/04/10 19:38:58 UTC

[camel] branch main updated: CAMEL-17923: Add the name of the constant to the header model (#7401)

This is an automated email from the ASF dual-hosted git repository.

nfilotto pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/camel.git


The following commit(s) were added to refs/heads/main by this push:
     new 6c9061bcc9a CAMEL-17923: Add the name of the constant to the header model (#7401)
6c9061bcc9a is described below

commit 6c9061bcc9a388e5129cd57c8a16e84649da3c68
Author: Nicolas Filotto <es...@users.noreply.github.com>
AuthorDate: Sun Apr 10 21:38:42 2022 +0200

    CAMEL-17923: Add the name of the constant to the header model (#7401)
    
    ## Motivation
    
    In the documentation of an header only the name of the header is provided but the good practice is to use the related constant instead of using a string directly, so we should rather propose the name of the constant that holds the name of the header to avoid typos and to ease potential future renaming.
    
    ## Modifications:
    
    * Add the field `constantName` to the model of the header that will contain the name of the header in the next formats:
      * In case of an interface or a class: `${declaring-class-name}#${constant-name}`
      * In case of an enum and `headersNameProvider` is set to a name of field: `${declaring-class-name}#${enum-constant-name}@${field-name}`
      * In case of an enum and `headersNameProvider` is set to a name of method: `${declaring-class-name}#${enum-constant-name}@${method-name}()`
      * In case of an enum by default: `${declaring-class-name}#${enum-constant-name}`
    * Add a new JS file with methods dedicated to the header template allowing to generate the link to the constants
---
 .../java/org/apache/camel/spi/UriEndpoint.java     |  4 +-
 docs/components/modules/ROOT/examples/js/camel.js  | 42 ++++++++++++++++++
 .../ROOT/partials/component-endpoint-headers.adoc  |  5 +--
 .../apache/camel/tooling/model/ComponentModel.java | 12 ++++++
 .../org/apache/camel/tooling/model/JsonMapper.java |  3 ++
 .../apache/camel/tooling/model/JsonMapperTest.java |  6 +++
 .../packaging/EndpointSchemaGeneratorMojo.java     | 50 ++++++++++++++--------
 .../packaging/EndpointSchemaGeneratorMojoTest.java | 16 ++++++-
 .../java/org/apache/camel/spi/UriEndpoint.java     |  4 +-
 9 files changed, 116 insertions(+), 26 deletions(-)

diff --git a/core/camel-api/src/generated/java/org/apache/camel/spi/UriEndpoint.java b/core/camel-api/src/generated/java/org/apache/camel/spi/UriEndpoint.java
index e9c64483bd9..00f97990130 100644
--- a/core/camel-api/src/generated/java/org/apache/camel/spi/UriEndpoint.java
+++ b/core/camel-api/src/generated/java/org/apache/camel/spi/UriEndpoint.java
@@ -189,8 +189,8 @@ public @interface UriEndpoint {
     Class<?> headersClass() default void.class;
 
     /**
-     * The name of the field to get or the name of the method to invoke to get the name of the headers defined in an
-     * enum.
+     * The name of the field to get or the name of the method without parameters to invoke to get the name of the
+     * headers defined in an enum.
      * <p/>
      * Only took into account if and only if the class defined as {@code headersClass} is an enum.
      * <p/>
diff --git a/docs/components/modules/ROOT/examples/js/camel.js b/docs/components/modules/ROOT/examples/js/camel.js
new file mode 100644
index 00000000000..82c2c14e2d3
--- /dev/null
+++ b/docs/components/modules/ROOT/examples/js/camel.js
@@ -0,0 +1,42 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.
+ */
+
+module.exports = {
+  extractConstantDisplayName: (name) => {
+    return name.split('#').pop().split('@').join('.')
+  },
+
+  extractConstantName: (name) => {
+    return name.split('#').pop().split('@').shift()
+  },
+
+  extractHeadersClass: (name) => {
+    return name.split('#').shift()
+  },
+
+  constantLink: (artifactId, name) => {
+      try {
+        return `https://javadoc.io/doc/org.apache.camel/${artifactId}/latest/`
+          + module.exports.extractHeadersClass(name).split('.').join('/') + '.html#'
+          + module.exports.extractConstantName(name)
+          + '[`' + module.exports.extractConstantDisplayName(name) + '`]'
+      } catch (e) {
+        console.log('error', e)
+        return e.msg()
+      }
+  },
+}
diff --git a/docs/components/modules/ROOT/partials/component-endpoint-headers.adoc b/docs/components/modules/ROOT/partials/component-endpoint-headers.adoc
index 94b11e8f68d..d5d182f7e69 100644
--- a/docs/components/modules/ROOT/partials/component-endpoint-headers.adoc
+++ b/docs/components/modules/ROOT/partials/component-endpoint-headers.adoc
@@ -1,11 +1,10 @@
 //component headers: START
 
 :tablespec: width="100%",cols="2,5a,^1,2",options="header"
-:cellformats: 'util.boldLink(path[2], "endpoint_header", value.group) \
+:cellformats: 'util.boldLink(path[2], "endpoint_header", value.group) + "\n\nConstant: " + camel.constantLink("{artifactid}",value.constantName) \
 |util.description(value) \
 |util.valueAsString(value.defaultValue) \
 |util.javaSimpleName(value.javaType)'
-include::jsonpath$example$json/{shortname}.json[query='$.component',formats='name,scheme,pascalcasescheme=util.pascalCase(scheme),syntax,apiSyntax', requires={requires}]
 include::jsonpathcount$example$json/{shortname}.json[queries='headercount=nodes$.headers.*']
 
 ifeval::[{headercount} != 0]
@@ -18,7 +17,7 @@ The {doctitle} component supports {headercount} message header(s), which is/are
 | Name | Description | Default | Type
 |===
 
-jsonpathTable::example$json/{shortname}.json['nodes$.headers.*',{cellformats},{requires}]
+jsonpathTable::example$json/{shortname}.json['nodes$.headers.*',{cellformats},'util=camel-website-util,camel=xref:js/camel.js']
 
 endif::[]
 // component headers: END
\ No newline at end of file
diff --git a/tooling/camel-tooling-model/src/main/java/org/apache/camel/tooling/model/ComponentModel.java b/tooling/camel-tooling-model/src/main/java/org/apache/camel/tooling/model/ComponentModel.java
index dfe31c0631e..d5df5019791 100644
--- a/tooling/camel-tooling-model/src/main/java/org/apache/camel/tooling/model/ComponentModel.java
+++ b/tooling/camel-tooling-model/src/main/java/org/apache/camel/tooling/model/ComponentModel.java
@@ -187,6 +187,18 @@ public class ComponentModel extends ArtifactModel<ComponentModel.ComponentOption
 
     public static class EndpointHeaderModel extends BaseOptionModel {
 
+        /**
+         * The name of the constant that defines the header.
+         */
+        private String constantName;
+
+        public String getConstantName() {
+            return constantName;
+        }
+
+        public void setConstantName(String constantName) {
+            this.constantName = constantName;
+        }
     }
 
     public static class ComponentOptionModel extends BaseOptionModel {
diff --git a/tooling/camel-tooling-model/src/main/java/org/apache/camel/tooling/model/JsonMapper.java b/tooling/camel-tooling-model/src/main/java/org/apache/camel/tooling/model/JsonMapper.java
index d828168c4fb..0b3db6dbc5e 100644
--- a/tooling/camel-tooling-model/src/main/java/org/apache/camel/tooling/model/JsonMapper.java
+++ b/tooling/camel-tooling-model/src/main/java/org/apache/camel/tooling/model/JsonMapper.java
@@ -97,6 +97,7 @@ public final class JsonMapper {
                 JsonObject mp = (JsonObject) entry.getValue();
                 EndpointHeaderModel header = new EndpointHeaderModel();
                 parseOption(mp, header, entry.getKey());
+                header.setConstantName(mp.getString("constantName"));
                 model.addEndpointHeader(header);
             }
         }
@@ -531,6 +532,8 @@ public final class JsonMapper {
         prop.put("setterMethod", option.getSetterMethod());
         if (option instanceof ComponentModel.ApiOptionModel) {
             prop.put("optional", ((ComponentModel.ApiOptionModel) option).isOptional());
+        } else if (option instanceof ComponentModel.EndpointHeaderModel) {
+            prop.put("constantName", ((ComponentModel.EndpointHeaderModel) option).getConstantName());
         }
         prop.entrySet().removeIf(e -> e.getValue() == null);
         prop.remove("prefix", "");
diff --git a/tooling/camel-tooling-model/src/test/java/org/apache/camel/tooling/model/JsonMapperTest.java b/tooling/camel-tooling-model/src/test/java/org/apache/camel/tooling/model/JsonMapperTest.java
index fc03afa90a2..6beecb46742 100644
--- a/tooling/camel-tooling-model/src/test/java/org/apache/camel/tooling/model/JsonMapperTest.java
+++ b/tooling/camel-tooling-model/src/test/java/org/apache/camel/tooling/model/JsonMapperTest.java
@@ -45,6 +45,7 @@ class JsonMapperTest {
         EndpointHeaderModel header = new EndpointHeaderModel();
         header.setName("Some Name");
         header.setDescription("Some Description");
+        header.setConstantName("Some constant Name");
         model.addEndpointHeader(header);
         String json = JsonMapper.createParameterJsonSchema(model);
         ComponentModel model2 = JsonMapper.generateComponentModel(json);
@@ -52,6 +53,7 @@ class JsonMapperTest {
         assertEquals(1, headers.size());
         assertEquals(header.getName(), headers.get(0).getName());
         assertEquals(header.getDescription(), headers.get(0).getDescription());
+        assertEquals(header.getConstantName(), headers.get(0).getConstantName());
     }
 
     @Test
@@ -60,10 +62,12 @@ class JsonMapperTest {
         EndpointHeaderModel header1 = new EndpointHeaderModel();
         header1.setName("Some Name");
         header1.setDescription("Some Description");
+        header1.setConstantName("Some constant Name");
         model.addEndpointHeader(header1);
         EndpointHeaderModel header2 = new EndpointHeaderModel();
         header2.setName("Some Name 2");
         header2.setDescription("Some Description 2");
+        header2.setConstantName("Some constant Name 2");
         model.addEndpointHeader(header2);
         String json = JsonMapper.createParameterJsonSchema(model);
         ComponentModel model2 = JsonMapper.generateComponentModel(json);
@@ -71,7 +75,9 @@ class JsonMapperTest {
         assertEquals(2, headers.size());
         assertEquals(header1.getName(), headers.get(0).getName());
         assertEquals(header1.getDescription(), headers.get(0).getDescription());
+        assertEquals(header1.getConstantName(), headers.get(0).getConstantName());
         assertEquals(header2.getName(), headers.get(1).getName());
         assertEquals(header2.getDescription(), headers.get(1).getDescription());
+        assertEquals(header2.getConstantName(), headers.get(1).getConstantName());
     }
 }
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 d0890ce1dc2..ce2dfa8f1cb 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
@@ -409,7 +409,7 @@ public class EndpointSchemaGeneratorMojo extends AbstractGeneratorMojo {
             getLog().debug(String.format("The java type %s could not be found", header.getJavaType()), e);
         }
         try {
-            header.setName(getHeaderName(field, headersNameProvider));
+            setHeaderNames(header, field, headersNameProvider);
             componentModel.addEndpointHeader(header);
         } catch (Exception e) {
             getLog().debug(String.format("The name of the header corresponding to the field %s in class %s cannot be retrieved",
@@ -420,31 +420,38 @@ public class EndpointSchemaGeneratorMojo extends AbstractGeneratorMojo {
     }
 
     /**
-     * The name of the header is:
+     * Set the name of the header and the name of the constant corresponding to the header.
+     * <p/>
+     * The name of the header and the name of the constant are set as follows:
      * <ul>
-     * <li>In case of an interface or a class: The value of the field as we assume that it is a {@code String}
-     * constant</li>
-     * <li>In case of an enum:
+     * <li><u>In case of an interface or a class:</u> <b>The name of the header</b> is the value of the field as we
+     * assume that it is a {@code String} constant and <b>the name of the constant</b> is in the following format
+     * <i>${declaring-class-name}#${constant-name}</i></li>
+     * <li><u>In case of an enum:</u>
      * <ul>
-     * <li>If headers name provider is set to a name of field: The value of this particular field for the corresponding
-     * enum constant</li>
-     * <li>If headers name provider is set to a name of method: The returned value of this particular method for the
-     * corresponding enum constant</li>
-     * <li>By default: The name of the enum constant</li>
+     * <li><u>If {@code headersNameProvider} is set to a name of field:</u> <b>The name of the header</b> is the value
+     * of this particular field for the corresponding enum constant and <b>the name of the constant</b> is in the
+     * following format <i>${declaring-class-name}#${enum-constant-name}@${field-name}</i></li>
+     * <li><u>If {@code headersNameProvider} is set to a name of method:</u> <b>The name of the header</b> is the
+     * returned value of this particular method for the corresponding enum constant and <b>the name of the constant</b>
+     * is in the following format <i>${declaring-class-name}#${enum-constant-name}@${method-name}()</i></li>
+     * <li><u>Otherwise:</u> <b>The name of the header</b> is the name of the enum constant and <b>the name of the
+     * constant</b> is in the following format <i>${declaring-class-name}#${enum-constant-name}</i></li>
      * </ul>
      * </li>
      * </ul>
      *
+     * @param  header              the header in which the name of the header and its corresponding constant should be
+     *                             set.
      * @param  field               the field corresponding to the name of a header.
      * @param  headersNameProvider the name of the field to get or the name of the method to invoke to get the name of
      *                             the headers.
-     * @return                     the name of the header corresponding to the given field.
      * @throws Exception           if an error occurred while getting the name of the header
      */
-    private String getHeaderName(Field field, String headersNameProvider) throws Exception {
+    private void setHeaderNames(EndpointHeaderModel header, Field field, String headersNameProvider) throws Exception {
+        final Class<?> declaringClass = field.getDeclaringClass();
         if (field.getType().isEnum()) {
             if (!headersNameProvider.isEmpty()) {
-                final Class<?> declaringClass = field.getDeclaringClass();
                 final Optional<?> value = Arrays.stream(declaringClass.getEnumConstants())
                         .filter(c -> ((Enum<?>) c).name().equals(field.getName()))
                         .findAny();
@@ -455,7 +462,10 @@ public class EndpointSchemaGeneratorMojo extends AbstractGeneratorMojo {
                             .findAny();
                     if (headersNameProviderField.isPresent()) {
                         getLog().debug("A field corresponding to the headers name provider has been found");
-                        return (String) headersNameProviderField.get().get(value.get());
+                        header.setConstantName(
+                                String.format("%s#%s@%s", declaringClass.getName(), field.getName(), headersNameProvider));
+                        header.setName((String) headersNameProviderField.get().get(value.get()));
+                        return;
                     }
                     getLog().debug(
                             String.format("No field %s could be found in the class %s", headersNameProvider, declaringClass));
@@ -464,15 +474,21 @@ public class EndpointSchemaGeneratorMojo extends AbstractGeneratorMojo {
                             .findAny();
                     if (headersNameProviderMethod.isPresent()) {
                         getLog().debug("A method without parameters corresponding to the headers name provider has been found");
-                        return (String) headersNameProviderMethod.get().invoke(value.get());
+                        header.setConstantName(
+                                String.format("%s#%s@%s()", declaringClass.getName(), field.getName(), headersNameProvider));
+                        header.setName((String) headersNameProviderMethod.get().invoke(value.get()));
+                        return;
                     }
                     getLog().debug(String.format("No method %s without parameters could be found in the class %s",
                             headersNameProvider, declaringClass));
                 }
             }
-            return field.getName();
+            header.setConstantName(String.format("%s#%s", declaringClass.getName(), field.getName()));
+            header.setName(field.getName());
+            return;
         }
-        return (String) field.get(null);
+        header.setConstantName(String.format("%s#%s", declaringClass.getName(), field.getName()));
+        header.setName((String) field.get(null));
     }
 
     /**
diff --git a/tooling/maven/camel-package-maven-plugin/src/test/java/org/apache/camel/maven/packaging/EndpointSchemaGeneratorMojoTest.java b/tooling/maven/camel-package-maven-plugin/src/test/java/org/apache/camel/maven/packaging/EndpointSchemaGeneratorMojoTest.java
index 5e4fc847169..08da2b57c84 100644
--- a/tooling/maven/camel-package-maven-plugin/src/test/java/org/apache/camel/maven/packaging/EndpointSchemaGeneratorMojoTest.java
+++ b/tooling/maven/camel-package-maven-plugin/src/test/java/org/apache/camel/maven/packaging/EndpointSchemaGeneratorMojoTest.java
@@ -65,7 +65,8 @@ class EndpointSchemaGeneratorMojoTest {
     @ValueSource(classes = {
             SomeEndpoint.class, SomeEndpointUsingEnumConstants.class, SomeEndpointUsingInterfaceConstants.class })
     void testCanRetrieveMetadataOfHeaders(Class<?> clazz) {
-        mojo.addEndpointHeaders(model, clazz.getAnnotation(UriEndpoint.class), "some");
+        UriEndpoint endpoint = clazz.getAnnotation(UriEndpoint.class);
+        mojo.addEndpointHeaders(model, endpoint, "some");
         List<EndpointHeaderModel> endpointHeaders = model.getEndpointHeaders();
         assertEquals(3, endpointHeaders.size());
         // Full
@@ -83,6 +84,8 @@ class EndpointSchemaGeneratorMojoTest {
         assertEquals("my label", headerFull.getLabel());
         assertEquals(3, headerFull.getEnums().size());
         assertEquals("my label", headerFull.getGroup());
+        assertEquals(String.format("%s#%s", endpoint.headersClass().getName(), headerFull.getName()),
+                headerFull.getConstantName());
         // Empty
         EndpointHeaderModel headerEmpty = endpointHeaders.get(1);
         assertEquals("header", headerEmpty.getKind());
@@ -99,6 +102,8 @@ class EndpointSchemaGeneratorMojoTest {
         assertTrue(headerEmpty.getLabel().isEmpty());
         assertNull(headerEmpty.getEnums());
         assertEquals("common", headerEmpty.getGroup());
+        assertEquals(String.format("%s#%s", endpoint.headersClass().getName(), headerEmpty.getName()),
+                headerEmpty.getConstantName());
         // Empty with Javadoc as description
         EndpointHeaderModel headerEmptyWithJavadoc = endpointHeaders.get(2);
         assertEquals("header", headerEmptyWithJavadoc.getKind());
@@ -115,6 +120,8 @@ class EndpointSchemaGeneratorMojoTest {
         assertTrue(headerEmptyWithJavadoc.getLabel().isEmpty());
         assertNull(headerEmptyWithJavadoc.getEnums());
         assertEquals("common", headerEmptyWithJavadoc.getGroup());
+        assertEquals(String.format("%s#%s", endpoint.headersClass().getName(), headerEmptyWithJavadoc.getName()),
+                headerEmptyWithJavadoc.getConstantName());
     }
 
     @Test
@@ -172,11 +179,16 @@ class EndpointSchemaGeneratorMojoTest {
     @ValueSource(classes = {
             SomeEndpointUsingEnumConstantsByField.class, SomeEndpointUsingEnumConstantsByMethod.class })
     void testEndpointWithNameProvider(Class<?> clazz) {
-        mojo.addEndpointHeaders(model, clazz.getAnnotation(UriEndpoint.class), "some");
+        UriEndpoint endpoint = clazz.getAnnotation(UriEndpoint.class);
+        mojo.addEndpointHeaders(model, endpoint, "some");
         List<EndpointHeaderModel> endpointHeaders = model.getEndpointHeaders();
         assertEquals(1, endpointHeaders.size());
         EndpointHeaderModel header = endpointHeaders.get(0);
         assertEquals("header", header.getKind());
         assertEquals("SomeName", header.getName());
+        assertEquals(
+                String.format("%s#SOME_VALUE@%s", endpoint.headersClass().getName(),
+                        endpoint.headersNameProvider() + (clazz.getName().contains("Method") ? "()" : "")),
+                header.getConstantName());
     }
 }
diff --git a/tooling/spi-annotations/src/main/java/org/apache/camel/spi/UriEndpoint.java b/tooling/spi-annotations/src/main/java/org/apache/camel/spi/UriEndpoint.java
index e9c64483bd9..00f97990130 100644
--- a/tooling/spi-annotations/src/main/java/org/apache/camel/spi/UriEndpoint.java
+++ b/tooling/spi-annotations/src/main/java/org/apache/camel/spi/UriEndpoint.java
@@ -189,8 +189,8 @@ public @interface UriEndpoint {
     Class<?> headersClass() default void.class;
 
     /**
-     * The name of the field to get or the name of the method to invoke to get the name of the headers defined in an
-     * enum.
+     * The name of the field to get or the name of the method without parameters to invoke to get the name of the
+     * headers defined in an enum.
      * <p/>
      * Only took into account if and only if the class defined as {@code headersClass} is an enum.
      * <p/>