This is an automated email from the ASF dual-hosted git repository. nfilotto pushed a commit to branch CAMEL-16628/headers-annotation in repository https://gitbox.apache.org/repos/asf/camel.git
commit edcecc37267e3f21dce61ce99f86121494700877 Author: Nicolas Filotto <[email protected]> AuthorDate: Fri Mar 11 11:35:12 2022 +0100 CAMEL-16628: Allow to generate doc about message headers --- .../java/org/apache/camel/spi/Metadata.java | 9 + .../ROOT/partials/component-endpoint-headers.adoc | 24 +++ .../apache/camel/tooling/model/ComponentModel.java | 13 ++ .../org/apache/camel/tooling/model/JsonMapper.java | 20 ++ .../apache/camel/tooling/model/JsonMapperTest.java | 77 ++++++++ tooling/maven/camel-package-maven-plugin/pom.xml | 52 ++++++ .../src/it/HeaderSupport/pom.xml | 70 +++++++ .../camel/component/foo/ConstantsSamePackage.java | 28 +++ .../apache/camel/component/foo/FooComponent.java | 26 +++ .../apache/camel/component/foo/FooEndpoint.java | 71 ++++++++ .../src/it/HeaderSupport/verify.groovy | 25 +++ .../camel-package-maven-plugin/src/it/settings.xml | 53 ++++++ .../packaging/EndpointSchemaGeneratorMojo.java | 201 +++++++++++++++++++-- .../packaging/EndpointSchemaGeneratorMojoTest.java | 102 +++++++++++ .../packaging/endpoint/SamePackageConstants.java | 46 +++++ .../maven/packaging/endpoint/SomeEndpoint.java | 96 ++++++++++ .../endpoint/SomeEndpointWithBadHeaders.java | 29 +++ .../endpoint/SomeEndpointWithoutHeaders.java | 23 +++ .../endpoint/other/OtherPackageConstants.java | 49 +++++ .../main/java/org/apache/camel/spi/Metadata.java | 9 + 20 files changed, 1009 insertions(+), 14 deletions(-) diff --git a/core/camel-api/src/generated/java/org/apache/camel/spi/Metadata.java b/core/camel-api/src/generated/java/org/apache/camel/spi/Metadata.java index f37ea43..a099566 100644 --- a/core/camel-api/src/generated/java/org/apache/camel/spi/Metadata.java +++ b/core/camel-api/src/generated/java/org/apache/camel/spi/Metadata.java @@ -132,4 +132,13 @@ public @interface Metadata { * specify which options each implementation only supports. */ String includeProperties() default ""; + + /** + * All the headers that are supported by the consumer and/or producer. + * <p/> + * The expected values are actually the constant expressions referring the name of the header like for example + * {@code KafkaConstants.PARTITION_KEY}. The metadata of each header are retrieved directly from the annotation + * {@code @Metadata} added to the corresponding constant. + */ + String[] headers() default {}; } diff --git a/docs/components/modules/ROOT/partials/component-endpoint-headers.adoc b/docs/components/modules/ROOT/partials/component-endpoint-headers.adoc new file mode 100644 index 0000000..94b11e8 --- /dev/null +++ b/docs/components/modules/ROOT/partials/component-endpoint-headers.adoc @@ -0,0 +1,24 @@ +//component headers: START + +:tablespec: width="100%",cols="2,5a,^1,2",options="header" +:cellformats: 'util.boldLink(path[2], "endpoint_header", value.group) \ +|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] +== Message Headers + +The {doctitle} component supports {headercount} message header(s), which is/are listed below: + +[{tablespec}] +|=== +| Name | Description | Default | Type +|=== + +jsonpathTable::example$json/{shortname}.json['nodes$.headers.*',{cellformats},{requires}] + +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 f4e5978..dfe31c0 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 @@ -37,6 +37,7 @@ public class ComponentModel extends ArtifactModel<ComponentModel.ComponentOption protected boolean lenientProperties; protected String verifiers; protected final List<EndpointOptionModel> endpointOptions = new ArrayList<>(); + protected final List<EndpointHeaderModel> headers = new ArrayList<>(); // lets sort apis A..Z so they are always in the same order protected final Collection<ApiModel> apiOptions = new TreeSet<>(Comparators.apiModelComparator()); @@ -160,6 +161,14 @@ public class ComponentModel extends ArtifactModel<ComponentModel.ComponentOption endpointOptions.add(option); } + public List<EndpointHeaderModel> getEndpointHeaders() { + return headers; + } + + public void addEndpointHeader(EndpointHeaderModel header) { + headers.add(header); + } + public List<EndpointOptionModel> getEndpointParameterOptions() { return endpointOptions.stream() .filter(o -> "parameter".equals(o.getKind())) @@ -176,6 +185,10 @@ public class ComponentModel extends ArtifactModel<ComponentModel.ComponentOption return apiOptions; } + public static class EndpointHeaderModel extends BaseOptionModel { + + } + 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 fde2830..86fe787 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 @@ -27,6 +27,7 @@ import java.util.TreeMap; import java.util.stream.Collectors; import org.apache.camel.tooling.model.ComponentModel.ComponentOptionModel; +import org.apache.camel.tooling.model.ComponentModel.EndpointHeaderModel; import org.apache.camel.tooling.model.ComponentModel.EndpointOptionModel; import org.apache.camel.tooling.model.DataFormatModel.DataFormatOptionModel; import org.apache.camel.tooling.model.EipModel.EipOptionModel; @@ -90,6 +91,15 @@ public final class JsonMapper { model.addComponentOption(option); } } + JsonObject headers = (JsonObject) obj.get("headers"); + if (headers != null) { + for (Map.Entry<String, Object> entry : headers.entrySet()) { + JsonObject mp = (JsonObject) entry.getValue(); + EndpointHeaderModel header = new EndpointHeaderModel(); + parseOption(mp, header, entry.getKey()); + model.addEndpointHeader(header); + } + } JsonObject mprp = (JsonObject) obj.get("properties"); if (mprp != null) { for (Map.Entry<String, Object> entry : mprp.entrySet()) { @@ -213,6 +223,10 @@ public final class JsonMapper { JsonObject wrapper = new JsonObject(); wrapper.put("component", obj); wrapper.put("componentProperties", asJsonObject(model.getComponentOptions())); + final List<EndpointHeaderModel> headers = model.getEndpointHeaders(); + if (!headers.isEmpty()) { + wrapper.put("headers", asJsonObject(headers)); + } wrapper.put("properties", asJsonObject(model.getEndpointOptions())); if (!model.getApiOptions().isEmpty()) { wrapper.put("apis", apiModelAsJsonObject(model.getApiOptions(), false)); @@ -527,6 +541,12 @@ public final class JsonMapper { return prop; } + public static JsonObject asJsonObject(EndpointHeaderModel header) { + JsonObject prop = new JsonObject(); + prop.put("description", header.getDescription()); + return prop; + } + public static MainModel generateMainModel(String json) { JsonObject obj = deserialize(json); return generateMainModel(obj); 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 new file mode 100644 index 0000000..fc03afa --- /dev/null +++ b/tooling/camel-tooling-model/src/test/java/org/apache/camel/tooling/model/JsonMapperTest.java @@ -0,0 +1,77 @@ +/* + * 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. + */ +package org.apache.camel.tooling.model; + +import java.util.List; + +import org.junit.jupiter.api.Test; + +import static org.apache.camel.tooling.model.ComponentModel.EndpointHeaderModel; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +/** + * The unit test class for {@link JsonMapper}. + */ +class JsonMapperTest { + + @Test + void testShouldSerializeAndDeserializeComponentWithoutHeaders() { + ComponentModel model = new ComponentModel(); + String json = JsonMapper.createParameterJsonSchema(model); + assertFalse(json.contains("\"headers\"")); + ComponentModel model2 = JsonMapper.generateComponentModel(json); + assertTrue(model2.getEndpointHeaders().isEmpty()); + } + + @Test + void testShouldSerializeAndDeserializeComponentWithOneHeader() { + ComponentModel model = new ComponentModel(); + EndpointHeaderModel header = new EndpointHeaderModel(); + header.setName("Some Name"); + header.setDescription("Some Description"); + model.addEndpointHeader(header); + String json = JsonMapper.createParameterJsonSchema(model); + ComponentModel model2 = JsonMapper.generateComponentModel(json); + List<EndpointHeaderModel> headers = model2.getEndpointHeaders(); + assertEquals(1, headers.size()); + assertEquals(header.getName(), headers.get(0).getName()); + assertEquals(header.getDescription(), headers.get(0).getDescription()); + } + + @Test + void testShouldSerializeAndDeserializeComponentWithSeveralHeaders() { + ComponentModel model = new ComponentModel(); + EndpointHeaderModel header1 = new EndpointHeaderModel(); + header1.setName("Some Name"); + header1.setDescription("Some Description"); + model.addEndpointHeader(header1); + EndpointHeaderModel header2 = new EndpointHeaderModel(); + header2.setName("Some Name 2"); + header2.setDescription("Some Description 2"); + model.addEndpointHeader(header2); + String json = JsonMapper.createParameterJsonSchema(model); + ComponentModel model2 = JsonMapper.generateComponentModel(json); + List<EndpointHeaderModel> headers = model2.getEndpointHeaders(); + assertEquals(2, headers.size()); + assertEquals(header1.getName(), headers.get(0).getName()); + assertEquals(header1.getDescription(), headers.get(0).getDescription()); + assertEquals(header2.getName(), headers.get(1).getName()); + assertEquals(header2.getDescription(), headers.get(1).getDescription()); + } +} diff --git a/tooling/maven/camel-package-maven-plugin/pom.xml b/tooling/maven/camel-package-maven-plugin/pom.xml index 29fcf2b..39c6839 100644 --- a/tooling/maven/camel-package-maven-plugin/pom.xml +++ b/tooling/maven/camel-package-maven-plugin/pom.xml @@ -188,6 +188,46 @@ </mojoDependencies> </configuration> </plugin> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-invoker-plugin</artifactId> + <configuration> + <cloneProjectsTo>${project.build.directory}/it</cloneProjectsTo> + <pomIncludes> + <pomInclude>*/pom.xml</pomInclude> + </pomIncludes> + <postBuildHookScript>verify</postBuildHookScript> + <localRepositoryPath>${project.build.directory}/local-repo</localRepositoryPath> + <settingsFile>src/it/settings.xml</settingsFile> + <goals> + <goal>clean</goal> + <goal>verify</goal> + </goals> + </configuration> + <executions> + <execution> + <id>integration-test</id> + <phase>integration-test</phase> + <goals> + <goal>install</goal> + <goal>integration-test</goal> + <goal>verify</goal> + </goals> + </execution> + </executions> + <dependencies> + <dependency> + <groupId>org.codehaus.groovy</groupId> + <artifactId>groovy</artifactId> + <version>${groovy-version}</version> + </dependency> + <dependency> + <groupId>org.apache.camel</groupId> + <artifactId>camel-tooling-model</artifactId> + <version>${project.version}</version> + </dependency> + </dependencies> + </plugin> </plugins> </build> @@ -205,5 +245,17 @@ </dependency> </dependencies> </profile> + <profile> + <id>fastinstall</id> + <activation> + <activeByDefault>true</activeByDefault> + <property> + <name>skipTests</name> + </property> + </activation> + <properties> + <invoker.skip>true</invoker.skip> + </properties> + </profile> </profiles> </project> diff --git a/tooling/maven/camel-package-maven-plugin/src/it/HeaderSupport/pom.xml b/tooling/maven/camel-package-maven-plugin/src/it/HeaderSupport/pom.xml new file mode 100644 index 0000000..2c2e648 --- /dev/null +++ b/tooling/maven/camel-package-maven-plugin/src/it/HeaderSupport/pom.xml @@ -0,0 +1,70 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + + 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. + +--> +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> + <modelVersion>4.0.0</modelVersion> + <groupId>org.apache.camel.integration.test</groupId> + <artifactId>header-support</artifactId> + <version>1.0-SNAPSHOT</version> + <packaging>jar</packaging> + <description>An IT ensuring that headers are supported.</description> + <properties> + <maven.compiler.source>11</maven.compiler.source> + <maven.compiler.target>11</maven.compiler.target> + </properties> + <dependencyManagement> + <dependencies> + <!-- Add Camel BOM --> + <dependency> + <groupId>org.apache.camel</groupId> + <artifactId>camel-bom</artifactId> + <version>@project.version@</version> + <type>pom</type> + <scope>import</scope> + </dependency> + </dependencies> + </dependencyManagement> + + <dependencies> + <dependency> + <groupId>org.apache.camel</groupId> + <artifactId>camel-core</artifactId> + </dependency> + </dependencies> + + <build> + <plugins> + <plugin> + <groupId>@project.groupId@</groupId> + <artifactId>@project.artifactId@</artifactId> + <version>@project.version@</version> + <executions> + <execution> + <id>generate</id> + <goals> + <goal>generate</goal> + </goals> + <phase>process-classes</phase> + </execution> + </executions> + </plugin> + </plugins> + </build> + +</project> diff --git a/tooling/maven/camel-package-maven-plugin/src/it/HeaderSupport/src/main/java/org/apache/camel/component/foo/ConstantsSamePackage.java b/tooling/maven/camel-package-maven-plugin/src/it/HeaderSupport/src/main/java/org/apache/camel/component/foo/ConstantsSamePackage.java new file mode 100644 index 0000000..34977df --- /dev/null +++ b/tooling/maven/camel-package-maven-plugin/src/it/HeaderSupport/src/main/java/org/apache/camel/component/foo/ConstantsSamePackage.java @@ -0,0 +1,28 @@ +/* + * 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. + */ +package org.apache.camel.component.foo; + +import org.apache.camel.spi.Metadata; + +public final class ConstantsSamePackage { + + @Metadata(description = "My Constant in same package") + public static final String SAME_PACKAGE_KEY = "SomeKeyName"; + + private ConstantsSamePackage() { + } +} \ No newline at end of file diff --git a/tooling/maven/camel-package-maven-plugin/src/it/HeaderSupport/src/main/java/org/apache/camel/component/foo/FooComponent.java b/tooling/maven/camel-package-maven-plugin/src/it/HeaderSupport/src/main/java/org/apache/camel/component/foo/FooComponent.java new file mode 100644 index 0000000..0e2d4e7 --- /dev/null +++ b/tooling/maven/camel-package-maven-plugin/src/it/HeaderSupport/src/main/java/org/apache/camel/component/foo/FooComponent.java @@ -0,0 +1,26 @@ +/* + * 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. + */ +package org.apache.camel.component.foo; + +import org.apache.camel.spi.annotations.Component; + +/** + * Foo Component + */ +@Component("foo") +public class FooComponent { +} \ No newline at end of file diff --git a/tooling/maven/camel-package-maven-plugin/src/it/HeaderSupport/src/main/java/org/apache/camel/component/foo/FooEndpoint.java b/tooling/maven/camel-package-maven-plugin/src/it/HeaderSupport/src/main/java/org/apache/camel/component/foo/FooEndpoint.java new file mode 100644 index 0000000..b994ecd --- /dev/null +++ b/tooling/maven/camel-package-maven-plugin/src/it/HeaderSupport/src/main/java/org/apache/camel/component/foo/FooEndpoint.java @@ -0,0 +1,71 @@ +/* + * 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. + */ +package org.apache.camel.component.foo; + +import org.apache.camel.Category; +import org.apache.camel.spi.Metadata; +import org.apache.camel.spi.UriEndpoint; +import org.apache.camel.spi.UriParam; +import org.apache.camel.spi.UriPath; + +@UriEndpoint(firstVersion = "1.1.0", scheme = "foo", extendsScheme = "foo", title = "FOO", + syntax = "foo:host:port", alternativeSyntax = "foo:host@port", + category = { Category.FILE }) +@Metadata(headers = ConstantsSamePackage.SAME_PACKAGE_KEY) +public class FooEndpoint { + + @UriPath(description = "Hostname of the Foo server") + @Metadata(required = true) + private String host; + @UriPath(description = "Port of the Foo server") + private int port; + @UriParam(label = "common", defaultValue = "5") + private int intervalSeconds = 5; + + public int getIntervalSeconds() { + return intervalSeconds; + } + + /** + * My interval in seconds. + */ + public void setIntervalSeconds(int intervalSeconds) { + this.intervalSeconds = intervalSeconds; + } + + public String getHost() { + return host; + } + + /** + * Hostname of the Foo server + */ + public void setHost(String host) { + this.host = host; + } + + public int getPort() { + return port; + } + + /** + * Port of the Foo server + */ + public void setPort(int port) { + this.port = port; + } +} \ No newline at end of file diff --git a/tooling/maven/camel-package-maven-plugin/src/it/HeaderSupport/verify.groovy b/tooling/maven/camel-package-maven-plugin/src/it/HeaderSupport/verify.groovy new file mode 100644 index 0000000..ab2dc14 --- /dev/null +++ b/tooling/maven/camel-package-maven-plugin/src/it/HeaderSupport/verify.groovy @@ -0,0 +1,25 @@ +/* + * 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. + */ + +import org.apache.camel.tooling.model.ComponentModel +import org.apache.camel.tooling.model.JsonMapper +File json = new File(basedir, "src/generated/resources/org/apache/camel/component/foo/foo.json") + +assert json.exists() + +ComponentModel component = JsonMapper.generateComponentModel(json.text) +assert component.getEndpointHeaders().size() == 1 diff --git a/tooling/maven/camel-package-maven-plugin/src/it/settings.xml b/tooling/maven/camel-package-maven-plugin/src/it/settings.xml new file mode 100644 index 0000000..c72c23c --- /dev/null +++ b/tooling/maven/camel-package-maven-plugin/src/it/settings.xml @@ -0,0 +1,53 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + + 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. + +--> +<settings> + <profiles> + <profile> + <id>it-repo</id> + <activation> + <activeByDefault>true</activeByDefault> + </activation> + <repositories> + <repository> + <id>local.central</id> + <url>@localRepositoryUrl@</url> + <releases> + <enabled>true</enabled> + </releases> + <snapshots> + <enabled>true</enabled> + </snapshots> + </repository> + </repositories> + <pluginRepositories> + <pluginRepository> + <id>local.central</id> + <url>@localRepositoryUrl@</url> + <releases> + <enabled>true</enabled> + </releases> + <snapshots> + <enabled>true</enabled> + </snapshots> + </pluginRepository> + </pluginRepositories> + </profile> + </profiles> +</settings> 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 6ff45ed..abfc771 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 @@ -64,6 +64,7 @@ import org.apache.camel.tooling.model.ApiModel; import org.apache.camel.tooling.model.BaseOptionModel; import org.apache.camel.tooling.model.ComponentModel; import org.apache.camel.tooling.model.ComponentModel.ComponentOptionModel; +import org.apache.camel.tooling.model.ComponentModel.EndpointHeaderModel; import org.apache.camel.tooling.model.ComponentModel.EndpointOptionModel; import org.apache.camel.tooling.model.JsonMapper; import org.apache.camel.tooling.model.SupportLevel; @@ -83,7 +84,10 @@ import org.jboss.forge.roaster._shade.org.eclipse.jdt.core.dom.ASTNode; import org.jboss.forge.roaster._shade.org.eclipse.jdt.core.dom.Javadoc; import org.jboss.forge.roaster.model.JavaDoc; import org.jboss.forge.roaster.model.JavaDocCapable; +import org.jboss.forge.roaster.model.StaticCapable; +import org.jboss.forge.roaster.model.source.AnnotationSource; import org.jboss.forge.roaster.model.source.FieldSource; +import org.jboss.forge.roaster.model.source.Import; import org.jboss.forge.roaster.model.source.JavaClassSource; import org.jboss.forge.roaster.model.source.MethodSource; import org.jboss.jandex.AnnotationInstance; @@ -92,7 +96,7 @@ import org.jboss.jandex.DotName; import org.jboss.jandex.IndexReader; import org.jboss.jandex.IndexView; -import static org.apache.camel.tooling.model.ComponentModel.*; +import static org.apache.camel.tooling.model.ComponentModel.ApiOptionModel; @Mojo(name = "generate-endpoint-schema", threadSafe = true, requiresDependencyResolution = ResolutionScope.COMPILE_PLUS_RUNTIME, defaultPhase = LifecyclePhase.PROCESS_CLASSES) @@ -258,6 +262,9 @@ public class EndpointSchemaGeneratorMojo extends AbstractGeneratorMojo { } } + // component headers + addEndpointHeaders(componentModel, classElement); + // endpoint options findClassProperties(componentModel, classElement, new HashSet<>(), "", null, null, false); @@ -291,6 +298,167 @@ public class EndpointSchemaGeneratorMojo extends AbstractGeneratorMojo { return componentModel; } + /** + * Retrieve the metadata added to the constants specified in the element {@code headers} of the annotation + * {@code Metadata}, convert the metadata retrieved into instances of {@link EndpointHeaderModel} and finally add + * the instances of {@link EndpointHeaderModel} to the given component model. + * + * @param componentModel the component model to which the headers should be added. + * @param classElement the class from which the annotation {@code Metadata} will be retrieved. + */ + void addEndpointHeaders(ComponentModel componentModel, Class<?> classElement) { + final Metadata componentMetadata = classElement.getAnnotation(Metadata.class); + if (componentMetadata == null || componentMetadata.headers().length == 0) { + return; + } + // There are headers to load + try { + final JavaClassSource source = javaClassSource(classElement.getName()); + final AnnotationSource<?> annotationSource = source.getAnnotation(Metadata.class); + if (annotationSource == null) { + getLog().warn(String.format("The annotation @Metadata could not be found by the parser in the class %s", + classElement.getName())); + return; + } + final String[] headers = annotationSource.getStringArrayValue("headers"); + if (headers == null) { + getLog().warn(String.format("The element headers of @Metadata could not be found by the parser in the class %s", + classElement.getName())); + return; + } + for (String headerRef : headers) { + getLog().debug(String.format("Header ref found %s", headerRef)); + addEndpointHeader(componentModel, source, headerRef); + } + } catch (Exception e) { + getLog().warn(String.format("The headers of %s could not be loaded", classElement.getName()), e); + } + } + + /** + * Identify the constant corresponding to the given header reference and retrieve the metadata added to it, convert + * the metadata retrieved into an instance of {@link EndpointHeaderModel} and finally add the instance of + * {@link EndpointHeaderModel} to the given component model. + * + * @param componentModel the component to which the header should be added. + * @param source the source of the file that contains the definition of the header references. + * @param headerRef the header reference to process. + */ + private void addEndpointHeader(ComponentModel componentModel, JavaClassSource source, String headerRef) { + final int lastIndex = headerRef.lastIndexOf('.'); + final String constantName; + final String qualifiedName; + if (lastIndex == -1) { + // No prefix + final Optional<Import> optionalImport = source.getImports().stream() + .filter(StaticCapable::isStatic) + .filter(imp -> imp.getSimpleName().equals(headerRef)) + .findFirst(); + if (optionalImport.isPresent()) { + constantName = headerRef; + final String importQualifiedName = optionalImport.get().getQualifiedName(); + qualifiedName = importQualifiedName.substring(0, importQualifiedName.length() - headerRef.length() - 1); + } else { + getLog().debug(String.format("The header %s defined in the class %s could not be found", headerRef, + source.getQualifiedName())); + return; + } + } else if (headerRef.startsWith(source.getPackage())) { + // Fully qualified + constantName = headerRef.substring(lastIndex + 1); + qualifiedName = headerRef.substring(0, lastIndex); + } else { + // With prefix + final String prefix = headerRef.substring(0, lastIndex); + final int firstIndex = prefix.indexOf('.'); + final String root = firstIndex == -1 ? prefix : prefix.substring(0, firstIndex); + final Optional<Import> optionalImport = source.getImports().stream() + .filter(imp -> !imp.isStatic()) + .filter(imp -> imp.getQualifiedName().endsWith(root)) + .findFirst(); + constantName = headerRef.substring(lastIndex + 1); + if (optionalImport.isPresent()) { + // In another package + if (firstIndex == -1) { + // No inner class + qualifiedName = optionalImport.get().getQualifiedName(); + } else { + // In inner class + qualifiedName = String.format("%s$%s", optionalImport.get().getQualifiedName(), + prefix.substring(firstIndex + 1).replace('.', '$')); + } + } else { + // In the same package + qualifiedName = String.format("%s.%s", source.getPackage(), prefix); + } + } + addEndpointHeader(componentModel, constantName, qualifiedName); + } + + /** + * Retrieve the metadata added to the given constant of the given class, convert the metadata retrieved into an + * instance of {@link EndpointHeaderModel} and finally add the instance of {@link EndpointHeaderModel} to the given + * component model. + * + * @param componentModel the component to which the header should be added. + * @param constantName the name of the constant from which the metadata defining the header should be extracted. + * @param qualifiedName the full qualified name of the class containing the constant. + */ + private void addEndpointHeader(ComponentModel componentModel, String constantName, String qualifiedName) { + getLog().debug( + String.format("Trying to add the constant %s in the class %s as header.", constantName, qualifiedName)); + try { + addEndpointHeader(componentModel, loadClass(qualifiedName).getDeclaredField(constantName)); + } catch (NoClassDefFoundError e) { + getLog().debug(String.format("The class %s could not be found", qualifiedName), e); + } catch (NoSuchFieldException e) { + getLog().debug(String.format("The field %s in class %s could not be found", constantName, qualifiedName), e); + } + } + + /** + * Retrieve the metadata added to the given field, convert the metadata retrieved into an instance of + * {@link EndpointHeaderModel} and finally add the instance of {@link EndpointHeaderModel} to the given component + * model. + * + * @param componentModel the component to which the header should be added. + * @param field the field corresponding to the constant from which the metadata should be extracted. + */ + private void addEndpointHeader(ComponentModel componentModel, Field field) { + final Metadata metadata = field.getAnnotation(Metadata.class); + if (metadata == null) { + getLog().debug(String.format("The field %s in class %s has no Metadata", field.getName(), + field.getDeclaringClass().getName())); + return; + } + final EndpointHeaderModel header = new EndpointHeaderModel(); + header.setDescription(metadata.description().trim()); + header.setKind("header"); + header.setDisplayName(metadata.displayName()); + header.setJavaType(metadata.javaType()); + header.setRequired(metadata.required()); + header.setDefaultValue(metadata.defaultValue()); + header.setDeprecated(field.isAnnotationPresent(Deprecated.class)); + header.setDeprecationNote(metadata.deprecationNote()); + header.setSecret(metadata.secret()); + header.setGroup(EndpointHelper.labelAsGroupName(metadata.label(), componentModel.isConsumerOnly(), + componentModel.isProducerOnly())); + header.setLabel(metadata.label()); + try { + header.setEnums(getEnums(metadata, header.getJavaType().isEmpty() ? null : loadClass(header.getJavaType()))); + } catch (NoClassDefFoundError e) { + getLog().debug(String.format("The java type %s could not be found", header.getJavaType()), e); + } + try { + field.trySetAccessible(); + header.setName((String) field.get(null)); + componentModel.addEndpointHeader(header); + } catch (IllegalAccessException e) { + getLog().debug(String.format("The field %s in class %s cannot be accessed", field.getName(), + field.getDeclaringClass().getName())); + } + } + private String getExcludedEnd(Metadata classElement) { String excludedEndpointProperties = ""; if (classElement != null) { @@ -730,19 +898,7 @@ public class EndpointSchemaGeneratorMojo extends AbstractGeneratorMojo { } // gather enums - List<String> enums = null; - if (metadata != null && !Strings.isNullOrEmpty(metadata.enums())) { - String[] values = metadata.enums().split(","); - enums = Stream.of(values).map(String::trim).collect(Collectors.toList()); - } else if (fieldType.isEnum()) { - enums = new ArrayList<>(); - for (Object val : fieldType.getEnumConstants()) { - String str = val.toString(); - if (!enums.contains(str)) { - enums.add(str); - } - } - } + List<String> enums = getEnums(metadata, fieldType); // the field type may be overloaded by another type boolean isDuration = false; @@ -839,6 +995,23 @@ public class EndpointSchemaGeneratorMojo extends AbstractGeneratorMojo { } } + private List<String> getEnums(Metadata metadata, Class<?> fieldType) { + List<String> enums = null; + if (metadata != null && !Strings.isNullOrEmpty(metadata.enums())) { + String[] values = metadata.enums().split(","); + enums = Stream.of(values).map(String::trim).collect(Collectors.toList()); + } else if (fieldType != null && fieldType.isEnum()) { + enums = new ArrayList<>(); + for (Object val : fieldType.getEnumConstants()) { + String str = val.toString(); + if (!enums.contains(str)) { + enums.add(str); + } + } + } + return enums; + } + private Field getFieldElement(Class<?> classElement, String fieldName) { Field fieldElement; try { 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 new file mode 100644 index 0000000..98890b5 --- /dev/null +++ b/tooling/maven/camel-package-maven-plugin/src/test/java/org/apache/camel/maven/packaging/EndpointSchemaGeneratorMojoTest.java @@ -0,0 +1,102 @@ +/* + * 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. + */ +package org.apache.camel.maven.packaging; + +import java.nio.file.Paths; +import java.util.List; + +import org.apache.camel.maven.packaging.endpoint.SomeEndpoint; +import org.apache.camel.maven.packaging.endpoint.SomeEndpointWithBadHeaders; +import org.apache.camel.maven.packaging.endpoint.SomeEndpointWithoutHeaders; +import org.apache.camel.tooling.model.ComponentModel; +import org.apache.camel.tooling.model.ComponentModel.EndpointHeaderModel; +import org.apache.maven.project.MavenProject; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertInstanceOf; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + +/** + * The unit test of {@link EndpointSchemaGeneratorMojo}. + */ +class EndpointSchemaGeneratorMojoTest { + + private final EndpointSchemaGeneratorMojo mojo = new EndpointSchemaGeneratorMojo(); + private final ComponentModel model = new ComponentModel(); + + @BeforeEach + void init() throws Exception { + mojo.sourceRoots = List.of( + Paths.get(EndpointSchemaGeneratorMojoTest.class.getResource("/").toURI()) + .resolve("../../src/test/java/")); + mojo.project = new MavenProject(); + } + + @Test + void testCanRetrieveMetadataOfHeaders() { + mojo.addEndpointHeaders(model, SomeEndpoint.class); + List<EndpointHeaderModel> endpointHeaders = model.getEndpointHeaders(); + assertEquals(18, endpointHeaders.size()); + for (int i = 1; i < endpointHeaders.size(); i++) { + EndpointHeaderModel header = endpointHeaders.get(i); + assertEquals("header", header.getKind()); + assertEquals(String.format("name-%d", i + 1), header.getName()); + assertEquals(String.format("key%d desc", i + 1), header.getDescription()); + assertTrue(header.getDisplayName().isEmpty()); + assertTrue(header.getJavaType().isEmpty()); + assertFalse(header.isRequired()); + assertInstanceOf(String.class, header.getDefaultValue()); + assertTrue(((String) header.getDefaultValue()).isEmpty()); + assertFalse(header.isDeprecated()); + assertTrue(header.getDeprecationNote().isEmpty()); + assertFalse(header.isSecret()); + assertTrue(header.getLabel().isEmpty()); + assertNull(header.getEnums()); + assertEquals("common", header.getGroup()); + } + EndpointHeaderModel header = endpointHeaders.get(0); + assertEquals("header", header.getKind()); + assertEquals("name-1", header.getName()); + assertEquals("key1 desc", header.getDescription()); + assertEquals("my display name", header.getDisplayName()); + assertEquals("org.apache.camel.maven.packaging.endpoint.SomeEndpoint$MyEnum", header.getJavaType()); + assertTrue(header.isRequired()); + assertEquals("VAL1", header.getDefaultValue()); + assertTrue(header.isDeprecated()); + assertEquals("my deprecated note", header.getDeprecationNote()); + assertTrue(header.isSecret()); + assertEquals("my label", header.getLabel()); + assertEquals(3, header.getEnums().size()); + assertEquals("my label", header.getGroup()); + } + + @Test + void testHeadersNotProperlyDefinedAreIgnored() { + mojo.addEndpointHeaders(model, SomeEndpointWithBadHeaders.class); + assertEquals(0, model.getEndpointHeaders().size()); + } + + @Test + void testEndpointWithoutHeadersAreIgnored() { + mojo.addEndpointHeaders(model, SomeEndpointWithoutHeaders.class); + assertEquals(0, model.getEndpointHeaders().size()); + } +} diff --git a/tooling/maven/camel-package-maven-plugin/src/test/java/org/apache/camel/maven/packaging/endpoint/SamePackageConstants.java b/tooling/maven/camel-package-maven-plugin/src/test/java/org/apache/camel/maven/packaging/endpoint/SamePackageConstants.java new file mode 100644 index 0000000..1d1debb --- /dev/null +++ b/tooling/maven/camel-package-maven-plugin/src/test/java/org/apache/camel/maven/packaging/endpoint/SamePackageConstants.java @@ -0,0 +1,46 @@ +/* + * 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. + */ +package org.apache.camel.maven.packaging.endpoint; + +import org.apache.camel.spi.Metadata; + +public final class SamePackageConstants { + @Metadata(description = "key2 desc") + static final String KEY_2 = "name-2"; + @Metadata(description = "key17 desc") + static final String KEY_17 = "name-17"; + + private SamePackageConstants() { + } + + public final class Inner { + @Metadata(description = "key7 desc") + public static final String KEY_7 = "name-7"; + @Metadata(description = "key11 desc") + public static final String KEY_11 = "name-11"; + + private Inner() { + } + } + + public static class InnerStatic { + @Metadata(description = "key8 desc") + public static final String KEY_8 = "name-8"; + @Metadata(description = "key12 desc") + public static final String KEY_12 = "name-12"; + } +} diff --git a/tooling/maven/camel-package-maven-plugin/src/test/java/org/apache/camel/maven/packaging/endpoint/SomeEndpoint.java b/tooling/maven/camel-package-maven-plugin/src/test/java/org/apache/camel/maven/packaging/endpoint/SomeEndpoint.java new file mode 100644 index 0000000..ba61373 --- /dev/null +++ b/tooling/maven/camel-package-maven-plugin/src/test/java/org/apache/camel/maven/packaging/endpoint/SomeEndpoint.java @@ -0,0 +1,96 @@ +/* + * 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. + */ +package org.apache.camel.maven.packaging.endpoint; + +import org.apache.camel.maven.packaging.endpoint.other.OtherPackageConstants; +import org.apache.camel.spi.Metadata; +import org.apache.camel.spi.UriPath; + +import static org.apache.camel.maven.packaging.endpoint.SamePackageConstants.Inner.KEY_7; +import static org.apache.camel.maven.packaging.endpoint.SamePackageConstants.InnerStatic.KEY_8; +import static org.apache.camel.maven.packaging.endpoint.SomeEndpoint.Inner.KEY_13; +import static org.apache.camel.maven.packaging.endpoint.SomeEndpoint.InnerStatic.KEY_14; +import static org.apache.camel.maven.packaging.endpoint.other.OtherPackageConstants.KEY_4; +import static org.apache.camel.maven.packaging.endpoint.other.OtherPackageConstants.Inner.KEY_9; +import static org.apache.camel.maven.packaging.endpoint.other.OtherPackageConstants.InnerStatic.KEY_10; + +@Metadata( + headers = { + SomeEndpoint.KEY_1, + SamePackageConstants.KEY_2, + OtherPackageConstants.KEY_3, + KEY_4, + OtherPackageConstants.Inner.KEY_5, + OtherPackageConstants.InnerStatic.KEY_6, + KEY_7, + KEY_8, + KEY_9, + KEY_10, + SamePackageConstants.Inner.KEY_11, + SamePackageConstants.InnerStatic.KEY_12, + KEY_13, + KEY_14, + SomeEndpoint.Inner.KEY_15, + SomeEndpoint.InnerStatic.KEY_16, + org.apache.camel.maven.packaging.endpoint.SamePackageConstants.KEY_17, + org.apache.camel.maven.packaging.endpoint.other.OtherPackageConstants.KEY_18 + }) +public class SomeEndpoint { + @Deprecated + @Metadata(description = "key1 desc", label = "my label", displayName = "my display name", + javaType = "org.apache.camel.maven.packaging.endpoint.SomeEndpoint$MyEnum", required = true, + defaultValue = "VAL1", deprecationNote = "my deprecated note", secret = true) + public static final String KEY_1 = "name-1"; + + @UriPath(description = "Hostname of the Foo server") + @Metadata(required = true) + private String host; + + public final class Inner { + @Metadata(description = "key13 desc") + public static final String KEY_13 = "name-13"; + @Metadata(description = "key15 desc") + public static final String KEY_15 = "name-15"; + + private Inner() { + } + } + + public static class InnerStatic { + @Metadata(description = "key14 desc") + public static final String KEY_14 = "name-14"; + @Metadata(description = "key16 desc") + public static final String KEY_16 = "name-16"; + } + + public String getHost() { + return host; + } + + /** + * Hostname of the Foo server + */ + public void setHost(String host) { + this.host = host; + } + + public enum MyEnum { + VAL1, + VAL2, + VAL3 + } +} diff --git a/tooling/maven/camel-package-maven-plugin/src/test/java/org/apache/camel/maven/packaging/endpoint/SomeEndpointWithBadHeaders.java b/tooling/maven/camel-package-maven-plugin/src/test/java/org/apache/camel/maven/packaging/endpoint/SomeEndpointWithBadHeaders.java new file mode 100644 index 0000000..94e2dec --- /dev/null +++ b/tooling/maven/camel-package-maven-plugin/src/test/java/org/apache/camel/maven/packaging/endpoint/SomeEndpointWithBadHeaders.java @@ -0,0 +1,29 @@ +/* + * 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. + */ +package org.apache.camel.maven.packaging.endpoint; + +import org.apache.camel.spi.Metadata; + +@Metadata( + headers = { "non-existing", SomeEndpointWithBadHeaders.NO_METADATA }) +public final class SomeEndpointWithBadHeaders { + public static final String NO_METADATA = "no-metadata"; + + private SomeEndpointWithBadHeaders() { + + } +} diff --git a/tooling/maven/camel-package-maven-plugin/src/test/java/org/apache/camel/maven/packaging/endpoint/SomeEndpointWithoutHeaders.java b/tooling/maven/camel-package-maven-plugin/src/test/java/org/apache/camel/maven/packaging/endpoint/SomeEndpointWithoutHeaders.java new file mode 100644 index 0000000..0d7fa93 --- /dev/null +++ b/tooling/maven/camel-package-maven-plugin/src/test/java/org/apache/camel/maven/packaging/endpoint/SomeEndpointWithoutHeaders.java @@ -0,0 +1,23 @@ +/* + * 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. + */ +package org.apache.camel.maven.packaging.endpoint; + +import org.apache.camel.spi.Metadata; + +@Metadata +public class SomeEndpointWithoutHeaders { +} diff --git a/tooling/maven/camel-package-maven-plugin/src/test/java/org/apache/camel/maven/packaging/endpoint/other/OtherPackageConstants.java b/tooling/maven/camel-package-maven-plugin/src/test/java/org/apache/camel/maven/packaging/endpoint/other/OtherPackageConstants.java new file mode 100644 index 0000000..afdd9ef --- /dev/null +++ b/tooling/maven/camel-package-maven-plugin/src/test/java/org/apache/camel/maven/packaging/endpoint/other/OtherPackageConstants.java @@ -0,0 +1,49 @@ +/* + * 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. + */ +package org.apache.camel.maven.packaging.endpoint.other; + +import org.apache.camel.spi.Metadata; + +public final class OtherPackageConstants { + @Metadata(description = "key3 desc") + public static final String KEY_3 = "name-3"; + @Metadata(description = "key4 desc") + public static final String KEY_4 = "name-4"; + @Metadata(description = "key18 desc") + public static final String KEY_18 = "name-18"; + + private OtherPackageConstants() { + + } + + public final class Inner { + @Metadata(description = "key5 desc") + public static final String KEY_5 = "name-5"; + @Metadata(description = "key9 desc") + public static final String KEY_9 = "name-9"; + + private Inner() { + } + } + + public static class InnerStatic { + @Metadata(description = "key6 desc") + public static final String KEY_6 = "name-6"; + @Metadata(description = "key10 desc") + public static final String KEY_10 = "name-10"; + } +} diff --git a/tooling/spi-annotations/src/main/java/org/apache/camel/spi/Metadata.java b/tooling/spi-annotations/src/main/java/org/apache/camel/spi/Metadata.java index f37ea43..a099566 100644 --- a/tooling/spi-annotations/src/main/java/org/apache/camel/spi/Metadata.java +++ b/tooling/spi-annotations/src/main/java/org/apache/camel/spi/Metadata.java @@ -132,4 +132,13 @@ public @interface Metadata { * specify which options each implementation only supports. */ String includeProperties() default ""; + + /** + * All the headers that are supported by the consumer and/or producer. + * <p/> + * The expected values are actually the constant expressions referring the name of the header like for example + * {@code KafkaConstants.PARTITION_KEY}. The metadata of each header are retrieved directly from the annotation + * {@code @Metadata} added to the corresponding constant. + */ + String[] headers() default {}; }
