CAMEL-8025: Added karaf commands to show component list.
Project: http://git-wip-us.apache.org/repos/asf/camel/repo Commit: http://git-wip-us.apache.org/repos/asf/camel/commit/7374b1da Tree: http://git-wip-us.apache.org/repos/asf/camel/tree/7374b1da Diff: http://git-wip-us.apache.org/repos/asf/camel/diff/7374b1da Branch: refs/heads/master Commit: 7374b1da11d051a1e5c72c3766e6396109e8eb2c Parents: 6c37f22 Author: Claus Ibsen <davscl...@apache.org> Authored: Mon Nov 10 13:18:17 2014 +0100 Committer: Claus Ibsen <davscl...@apache.org> Committed: Mon Nov 10 14:51:12 2014 +0100 ---------------------------------------------------------------------- .../management/mbean/ManagedCamelContext.java | 5 +- .../camel/component/event/EventComponent.java | 7 +- .../camel/component/event/EventEndpoint.java | 5 +- .../karaf/commands/CamelCommandSupport.java | 8 + .../camel/karaf/commands/CamelController.java | 10 + .../camel/karaf/commands/ComponentList.java | 190 +++++++++++++++++++ .../commands/internal/CamelControllerImpl.java | 70 +++++++ .../OSGI-INF/blueprint/camel-commands.xml | 9 + .../tools/apt/EndpointAnnotationProcessor.java | 36 +++- 9 files changed, 325 insertions(+), 15 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/camel/blob/7374b1da/camel-core/src/main/java/org/apache/camel/management/mbean/ManagedCamelContext.java ---------------------------------------------------------------------- diff --git a/camel-core/src/main/java/org/apache/camel/management/mbean/ManagedCamelContext.java b/camel-core/src/main/java/org/apache/camel/management/mbean/ManagedCamelContext.java index b9f0023..2cd0aa4 100644 --- a/camel-core/src/main/java/org/apache/camel/management/mbean/ManagedCamelContext.java +++ b/camel-core/src/main/java/org/apache/camel/management/mbean/ManagedCamelContext.java @@ -495,10 +495,11 @@ public class ManagedCamelContext extends ManagedPerformanceCounter implements Ti String name = entry.getKey(); String description = null; // the status can be: - // - loaded = in use + // - in use = used by Camel // - classpath = on the classpath // - release = available from the Apache Camel release - String status = context.hasComponent(name) != null ? "loaded" : "classpath"; + // TODO: gather list of components in the Camel release + String status = context.hasComponent(name) != null ? "in use" : "on classpath"; String type = null; String groupId = null; String artifactId = null; http://git-wip-us.apache.org/repos/asf/camel/blob/7374b1da/components/camel-spring/src/main/java/org/apache/camel/component/event/EventComponent.java ---------------------------------------------------------------------- diff --git a/components/camel-spring/src/main/java/org/apache/camel/component/event/EventComponent.java b/components/camel-spring/src/main/java/org/apache/camel/component/event/EventComponent.java index 9296f64..acb49fb 100644 --- a/components/camel-spring/src/main/java/org/apache/camel/component/event/EventComponent.java +++ b/components/camel-spring/src/main/java/org/apache/camel/component/event/EventComponent.java @@ -21,6 +21,7 @@ import java.util.Map; import java.util.Set; import org.apache.camel.impl.DefaultComponent; +import org.apache.camel.impl.UriEndpointComponent; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.BeansException; @@ -31,19 +32,21 @@ import org.springframework.context.ConfigurableApplicationContext; /** * An <a href="http://camel.apache.org/event.html">Event Component</a> - * for working with Spring ApplicationEvents + * for working with Spring ApplicationEvents. * * @version */ -public class EventComponent extends DefaultComponent implements ApplicationContextAware { +public class EventComponent extends UriEndpointComponent implements ApplicationContextAware { private static final Logger LOG = LoggerFactory.getLogger(EventComponent.class); private ApplicationContext applicationContext; private final Set<EventEndpoint> endpoints = new LinkedHashSet<EventEndpoint>(); public EventComponent() { + super(EventEndpoint.class); } public EventComponent(ApplicationContext applicationContext) { + super(EventEndpoint.class); setApplicationContext(applicationContext); } http://git-wip-us.apache.org/repos/asf/camel/blob/7374b1da/components/camel-spring/src/main/java/org/apache/camel/component/event/EventEndpoint.java ---------------------------------------------------------------------- diff --git a/components/camel-spring/src/main/java/org/apache/camel/component/event/EventEndpoint.java b/components/camel-spring/src/main/java/org/apache/camel/component/event/EventEndpoint.java index fceea03..483bd5f 100644 --- a/components/camel-spring/src/main/java/org/apache/camel/component/event/EventEndpoint.java +++ b/components/camel-spring/src/main/java/org/apache/camel/component/event/EventEndpoint.java @@ -23,6 +23,7 @@ import org.apache.camel.impl.DefaultEndpoint; import org.apache.camel.impl.DefaultProducer; import org.apache.camel.processor.loadbalancer.LoadBalancer; import org.apache.camel.processor.loadbalancer.TopicLoadBalancer; +import org.apache.camel.spi.UriEndpoint; import org.apache.camel.util.ObjectHelper; import org.springframework.beans.BeansException; import org.springframework.context.ApplicationContext; @@ -31,13 +32,13 @@ import org.springframework.context.ApplicationEvent; import static org.apache.camel.util.ObjectHelper.wrapRuntimeCamelException; - /** * An <a href="http://camel.apache.org/event.html">Event Endpoint</a> * for working with Spring ApplicationEvents * * @version */ +@UriEndpoint(scheme = "spring-event", consumerClass = EventConsumer.class) public class EventEndpoint extends DefaultEndpoint implements ApplicationContextAware { private LoadBalancer loadBalancer; private ApplicationContext applicationContext; @@ -50,7 +51,7 @@ public class EventEndpoint extends DefaultEndpoint implements ApplicationContext /** * <b>Note:</b> It is preferred to create endpoints using the associated * component. - * @param endpointUri + * @deprecated */ @Deprecated public EventEndpoint(String endpointUri) { http://git-wip-us.apache.org/repos/asf/camel/blob/7374b1da/platforms/karaf/commands/src/main/java/org/apache/camel/karaf/commands/CamelCommandSupport.java ---------------------------------------------------------------------- diff --git a/platforms/karaf/commands/src/main/java/org/apache/camel/karaf/commands/CamelCommandSupport.java b/platforms/karaf/commands/src/main/java/org/apache/camel/karaf/commands/CamelCommandSupport.java index a1edfe2..6076af2 100644 --- a/platforms/karaf/commands/src/main/java/org/apache/camel/karaf/commands/CamelCommandSupport.java +++ b/platforms/karaf/commands/src/main/java/org/apache/camel/karaf/commands/CamelCommandSupport.java @@ -29,4 +29,12 @@ public abstract class CamelCommandSupport extends OsgiCommandSupport { this.camelController = camelController; } + String safeNull(String s) { + if (s == null) { + return ""; + } else { + return s; + } + } + } http://git-wip-us.apache.org/repos/asf/camel/blob/7374b1da/platforms/karaf/commands/src/main/java/org/apache/camel/karaf/commands/CamelController.java ---------------------------------------------------------------------- diff --git a/platforms/karaf/commands/src/main/java/org/apache/camel/karaf/commands/CamelController.java b/platforms/karaf/commands/src/main/java/org/apache/camel/karaf/commands/CamelController.java index aa5bdf8..2495a0c 100644 --- a/platforms/karaf/commands/src/main/java/org/apache/camel/karaf/commands/CamelController.java +++ b/platforms/karaf/commands/src/main/java/org/apache/camel/karaf/commands/CamelController.java @@ -112,7 +112,17 @@ public interface CamelController { * @param uri the endpoint uri * @param allOptions whether to explain all options, or only the explicit configured options from the uri * @return a JSON schema with explanation of the options + * @throws java.lang.Exception is thrown if error loading resources to explain the endpoint */ String explainEndpoint(String camelContextName, String uri, boolean allOptions) throws Exception; + /** + * Lists all components and include information + * + * @param camelContextName the Camel context. + * @return a list of key/value pairs with component information + * @throws java.lang.Exception is thrown if error loading resources to gather component information + */ + List<Map<String, String>> listComponents(String camelContextName) throws Exception; + } \ No newline at end of file http://git-wip-us.apache.org/repos/asf/camel/blob/7374b1da/platforms/karaf/commands/src/main/java/org/apache/camel/karaf/commands/ComponentList.java ---------------------------------------------------------------------- diff --git a/platforms/karaf/commands/src/main/java/org/apache/camel/karaf/commands/ComponentList.java b/platforms/karaf/commands/src/main/java/org/apache/camel/karaf/commands/ComponentList.java new file mode 100644 index 0000000..1c196a3 --- /dev/null +++ b/platforms/karaf/commands/src/main/java/org/apache/camel/karaf/commands/ComponentList.java @@ -0,0 +1,190 @@ +/** + * 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.karaf.commands; + +import java.io.PrintStream; +import java.util.Hashtable; +import java.util.List; +import java.util.Map; + +import org.apache.felix.gogo.commands.Argument; +import org.apache.felix.gogo.commands.Command; +import org.apache.felix.gogo.commands.Option; + +/** + * List the Camel components available in the Karaf instance. + */ +@Command(scope = "camel", name = "component-list", description = "Lists all Camel components available in CamelContexts.") +public class ComponentList extends CamelCommandSupport { + + private static final String NAME_COLUMN_LABEL = "Name"; + private static final String STATUS_COLUMN_LABEL = "Status"; + private static final String MAVEN_COLUMN_LABEL = "Maven Coordinate"; + private static final String DESCRIPTION_COLUMN_LABEL = "Description"; + + private static final int DEFAULT_COLUMN_WIDTH_INCREMENT = 0; + private static final String DEFAULT_FIELD_PREAMBLE = " "; + private static final String DEFAULT_FIELD_POSTAMBLE = " "; + private static final String DEFAULT_HEADER_PREAMBLE = " "; + private static final String DEFAULT_HEADER_POSTAMBLE = " "; + private static final int DEFAULT_FORMAT_BUFFER_LENGTH = 24; + // descriptions can be very long so clip by default after 120 chars + private static final int MAX_COLUMN_WIDTH = 120; + private static final int MIN_COLUMN_WIDTH = 12; + + @Argument(index = 0, name = "name", description = "The Camel context name where to look for the components", required = true, multiValued = false) + String name; + + @Option(name = "--verbose", aliases = "-v", description = "Verbose output which shows more information", + required = false, multiValued = false, valueToShowInHelp = "false") + boolean verbose = false; + + protected Object doExecute() throws Exception { + List<Map<String, String>> components = camelController.listComponents(name); + + if (components == null || components.isEmpty()) { + return null; + } + + final Map<String, Integer> columnWidths = computeColumnWidths(components); + final String headerFormat = buildFormatString(columnWidths, true, verbose); + final String rowFormat = buildFormatString(columnWidths, false, verbose); + final PrintStream out = System.out; + + if (verbose) { + out.println(String.format(headerFormat, NAME_COLUMN_LABEL, STATUS_COLUMN_LABEL, MAVEN_COLUMN_LABEL, DESCRIPTION_COLUMN_LABEL)); + out.println(String.format(headerFormat, "----", "------", "----------------", "-----------")); + } else { + out.println(String.format(headerFormat, NAME_COLUMN_LABEL, DESCRIPTION_COLUMN_LABEL)); + out.println(String.format(headerFormat, "----", "-----------")); + } + for (final Map<String, String> component : components) { + if (verbose) { + String name = safeNull(component.get("name")); + String status = safeNull(component.get("status")); + String maven = ""; + if (component.containsKey("groupId") && component.containsKey("artifactId") && component.containsKey("version")) { + maven = component.get("groupId") + "/" + component.get("artifactId") + "/" + component.get("version"); + } + String description = safeNull(component.get("description")); + out.println(String.format(rowFormat, name, status, maven, description)); + } else { + String name = safeNull(component.get("name")); + String description = safeNull(component.get("description")); + out.println(String.format(rowFormat, name, description)); + } + } + + return null; + } + + private Map<String, Integer> computeColumnWidths(final Iterable<Map<String, String>> components) throws Exception { + if (components == null) { + return null; + } else { + // some of the options is optional so we need to start from 1 + int maxNameLen = 1; + int maxStatusLen = 1; + int maxMavenLen = 1; + int maxDescriptionLen = 1; + + for (final Map<String, String> component : components) { + + // grab the information and compute max len + String name = component.get("name"); + if (name != null) { + maxNameLen = Math.max(maxNameLen, name.length()); + } + String status = component.get("status"); + if (status != null) { + maxStatusLen = Math.max(maxStatusLen, status.length()); + } + String type = component.get("type"); + if (component.containsKey("groupId") && component.containsKey("artifactId") && component.containsKey("version")) { + String mvn = component.get("groupId") + "/" + component.get("artifactId") + "/" + component.get("version"); + maxMavenLen = Math.max(maxMavenLen, mvn.length()); + } + String description = component.get("description"); + if (description != null) { + maxDescriptionLen = Math.max(maxDescriptionLen, description.length()); + } + } + + final Map<String, Integer> retval = new Hashtable<String, Integer>(4); + retval.put(NAME_COLUMN_LABEL, maxNameLen); + retval.put(STATUS_COLUMN_LABEL, maxStatusLen); + retval.put(MAVEN_COLUMN_LABEL, maxMavenLen); + retval.put(DESCRIPTION_COLUMN_LABEL, maxDescriptionLen); + + return retval; + } + } + + private String buildFormatString(Map<String, Integer> columnWidths, boolean isHeader, boolean isVerbose) { + final String fieldPreamble; + final String fieldPostamble; + final int columnWidthIncrement; + + if (isHeader) { + fieldPreamble = DEFAULT_HEADER_PREAMBLE; + fieldPostamble = DEFAULT_HEADER_POSTAMBLE; + } else { + fieldPreamble = DEFAULT_FIELD_PREAMBLE; + fieldPostamble = DEFAULT_FIELD_POSTAMBLE; + } + columnWidthIncrement = DEFAULT_COLUMN_WIDTH_INCREMENT; + + if (verbose) { + int nameLen = Math.min(columnWidths.get(NAME_COLUMN_LABEL) + columnWidthIncrement, getMaxColumnWidth()); + int statusLen = Math.min(columnWidths.get(STATUS_COLUMN_LABEL) + columnWidthIncrement, getMaxColumnWidth()); + int mavenLen = Math.min(columnWidths.get(MAVEN_COLUMN_LABEL) + columnWidthIncrement, getMaxColumnWidth()); + int descriptionLen = Math.min(columnWidths.get(DESCRIPTION_COLUMN_LABEL) + columnWidthIncrement, getMaxColumnWidth()); + + nameLen = Math.max(MIN_COLUMN_WIDTH, nameLen); + statusLen = Math.max(MIN_COLUMN_WIDTH, statusLen); + mavenLen = Math.max(MIN_COLUMN_WIDTH, mavenLen); + // last row does not have min width + + final StringBuilder retval = new StringBuilder(DEFAULT_FORMAT_BUFFER_LENGTH); + retval.append(fieldPreamble).append("%-").append(nameLen).append('.').append(nameLen).append('s').append(fieldPostamble).append(' '); + retval.append(fieldPreamble).append("%-").append(statusLen).append('.').append(statusLen).append('s').append(fieldPostamble).append(' '); + retval.append(fieldPreamble).append("%-").append(mavenLen).append('.').append(mavenLen).append('s').append(fieldPostamble).append(' '); + retval.append(fieldPreamble).append("%-").append(descriptionLen).append('.').append(descriptionLen).append('s').append(fieldPostamble).append(' '); + return retval.toString(); + } else { + int nameLen = Math.min(columnWidths.get(NAME_COLUMN_LABEL) + columnWidthIncrement, getMaxColumnWidth()); + int descriptionLen = Math.min(columnWidths.get(DESCRIPTION_COLUMN_LABEL) + columnWidthIncrement, getMaxColumnWidth()); + + nameLen = Math.max(MIN_COLUMN_WIDTH, nameLen); + // last row does not have min width + + final StringBuilder retval = new StringBuilder(DEFAULT_FORMAT_BUFFER_LENGTH); + retval.append(fieldPreamble).append("%-").append(nameLen).append('.').append(nameLen).append('s').append(fieldPostamble).append(' '); + retval.append(fieldPreamble).append("%-").append(descriptionLen).append('.').append(descriptionLen).append('s').append(fieldPostamble).append(' '); + return retval.toString(); + } + } + + private int getMaxColumnWidth() { + if (verbose) { + return Integer.MAX_VALUE; + } else { + return MAX_COLUMN_WIDTH; + } + } + +} http://git-wip-us.apache.org/repos/asf/camel/blob/7374b1da/platforms/karaf/commands/src/main/java/org/apache/camel/karaf/commands/internal/CamelControllerImpl.java ---------------------------------------------------------------------- diff --git a/platforms/karaf/commands/src/main/java/org/apache/camel/karaf/commands/internal/CamelControllerImpl.java b/platforms/karaf/commands/src/main/java/org/apache/camel/karaf/commands/internal/CamelControllerImpl.java index 07bfcbb..0c8231a 100644 --- a/platforms/karaf/commands/src/main/java/org/apache/camel/karaf/commands/internal/CamelControllerImpl.java +++ b/platforms/karaf/commands/src/main/java/org/apache/camel/karaf/commands/internal/CamelControllerImpl.java @@ -19,9 +19,11 @@ package org.apache.camel.karaf.commands.internal; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; +import java.util.HashMap; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; +import java.util.Properties; import org.apache.camel.CamelContext; import org.apache.camel.Endpoint; @@ -30,6 +32,7 @@ import org.apache.camel.karaf.commands.CamelController; import org.apache.camel.model.RouteDefinition; import org.apache.camel.model.rest.RestDefinition; import org.apache.camel.spi.RestRegistry; +import org.apache.camel.util.JsonSchemaHelper; import org.osgi.framework.BundleContext; import org.osgi.framework.ServiceReference; import org.slf4j.Logger; @@ -232,4 +235,71 @@ public class CamelControllerImpl implements CamelController { } return context.explainEndpointJson(uri, allOptions); } + + public List<Map<String, String>> listComponents(String camelContextName) throws Exception { + CamelContext context = this.getCamelContext(camelContextName); + if (context == null) { + return null; + } + + List<Map<String, String>> answer = new ArrayList<Map<String, String>>(); + + // find all components + Map<String, Properties> components = context.findComponents(); + + // gather component detail for each component + for (Map.Entry<String, Properties> entry : components.entrySet()) { + String name = entry.getKey(); + String description = null; + // the status can be: + // - loaded = in use + // - classpath = on the classpath + // - release = available from the Apache Camel release + String status = context.hasComponent(name) != null ? "in use" : "on classpath"; + String type = null; + String groupId = null; + String artifactId = null; + String version = null; + + // load component json data, and parse it to gather the component meta-data + String json = context.getComponentParameterJsonSchema(name); + List<Map<String, String>> rows = JsonSchemaHelper.parseJsonSchema("component", json, false); + for (Map<String, String> row : rows) { + if (row.containsKey("description")) { + description = row.get("description"); + } else if (row.containsKey("javaType")) { + type = row.get("javaType"); + } else if (row.containsKey("groupId")) { + groupId = row.get("groupId"); + } else if (row.containsKey("artifactId")) { + artifactId = row.get("artifactId"); + } else if (row.containsKey("version")) { + version = row.get("version"); + } + } + + Map<String, String> row = new HashMap<>(); + row.put("name", name); + row.put("status", status); + if (description != null) { + row.put("description", description); + } + if (type != null) { + row.put("type", type); + } + if (groupId != null) { + row.put("groupId", groupId); + } + if (artifactId != null) { + row.put("artifactId", artifactId); + } + if (version != null) { + row.put("version", version); + } + + answer.add(row); + } + + return answer; + } } http://git-wip-us.apache.org/repos/asf/camel/blob/7374b1da/platforms/karaf/commands/src/main/resources/OSGI-INF/blueprint/camel-commands.xml ---------------------------------------------------------------------- diff --git a/platforms/karaf/commands/src/main/resources/OSGI-INF/blueprint/camel-commands.xml b/platforms/karaf/commands/src/main/resources/OSGI-INF/blueprint/camel-commands.xml index 11e3fc4..d3a38f0 100644 --- a/platforms/karaf/commands/src/main/resources/OSGI-INF/blueprint/camel-commands.xml +++ b/platforms/karaf/commands/src/main/resources/OSGI-INF/blueprint/camel-commands.xml @@ -221,6 +221,15 @@ <null/> </completers> </command> + <command name="camel/component-list"> + <action class="org.apache.camel.karaf.commands.ComponentList"> + <property name="camelController" ref="camelController"/> + </action> + <completers> + <ref component-id="camelContextCompleter"/> + <null/> + </completers> + </command> </command-bundle> <bean id="camelContextCompleter" class="org.apache.camel.karaf.commands.completers.CamelContextCompleter"> http://git-wip-us.apache.org/repos/asf/camel/blob/7374b1da/tooling/apt/src/main/java/org/apache/camel/tools/apt/EndpointAnnotationProcessor.java ---------------------------------------------------------------------- diff --git a/tooling/apt/src/main/java/org/apache/camel/tools/apt/EndpointAnnotationProcessor.java b/tooling/apt/src/main/java/org/apache/camel/tools/apt/EndpointAnnotationProcessor.java index 675b5fe..0c2ffe8 100644 --- a/tooling/apt/src/main/java/org/apache/camel/tools/apt/EndpointAnnotationProcessor.java +++ b/tooling/apt/src/main/java/org/apache/camel/tools/apt/EndpointAnnotationProcessor.java @@ -155,10 +155,8 @@ public class EndpointAnnotationProcessor extends AbstractProcessor { Set<EndpointOption> endpointOptions = new LinkedHashSet<>(); findClassProperties(roundEnv, endpointOptions, classElement, ""); - if (!endpointOptions.isEmpty()) { - String json = createParameterJsonSchema(componentModel, endpointOptions); - writer.println(json); - } + String json = createParameterJsonSchema(componentModel, endpointOptions); + writer.println(json); } public String createParameterJsonSchema(ComponentModel componentModel, Set<EndpointOption> options) { @@ -166,7 +164,7 @@ public class EndpointAnnotationProcessor extends AbstractProcessor { // component model buffer.append("\n \"component\": {"); buffer.append("\n \"scheme\": \"" + componentModel.getScheme() + "\","); - buffer.append("\n \"description\": \"" + sanitizeDescription(componentModel.getDescription()) + "\","); + buffer.append("\n \"description\": \"" + componentModel.getDescription() + "\","); buffer.append("\n \"javaType\": \"" + componentModel.getJavaType() + "\","); buffer.append("\n \"groupId\": \"" + componentModel.getGroupId() + "\","); buffer.append("\n \"artifactId\": \"" + componentModel.getArtifactId() + "\","); @@ -241,10 +239,28 @@ public class EndpointAnnotationProcessor extends AbstractProcessor { if (data != null) { Map<String, String> map = parseAsMap(data); // now we have a lot more data, so we need to load it as key/value - model.setDescription(map.get("projectDescription")); - model.setGroupId(map.get("groupId")); - model.setArtifactId(map.get("artifactId")); - model.setVersionId(map.get("version")); + // need to sanitize the description first + String doc = map.get("projectDescription"); + if (doc != null) { + model.setDescription(sanitizeDescription(doc)); + } else { + model.setDescription(""); + } + if (map.containsKey("groupId")) { + model.setGroupId(map.get("groupId")); + } else { + model.setGroupId(""); + } + if (map.containsKey("artifactId")) { + model.setArtifactId(map.get("artifactId")); + } else { + model.setArtifactId(""); + } + if (map.containsKey("version")) { + model.setVersionId(map.get("version")); + } else { + model.setVersionId(""); + } } // favor to use class javadoc of component as description @@ -254,6 +270,8 @@ public class EndpointAnnotationProcessor extends AbstractProcessor { if (typeElement != null) { String doc = elementUtils.getDocComment(typeElement); if (doc != null) { + // need to sanitize the description first + doc = sanitizeDescription(doc); // grab the first sentence only as this is for short description int idx = doc.indexOf('.'); if (idx != -1) {