/** * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * * Copyright (c) 1997-2010 Oracle and/or its affiliates. All rights reserved. * Portions Copyright 2013-2017 Philip Helger + contributors * * The contents of this file are subject to the terms of either the GNU * General Public License Version 2 only ("GPL") or the Common Development * and Distribution License("CDDL") (collectively, the "License"). You * may not use this file except in compliance with the License. You can * obtain a copy of the License at * https://glassfish.dev.java.net/public/CDDL+GPL_1_1.html * or packager/legal/LICENSE.txt. See the License for the specific * language governing permissions and limitations under the License. * * When distributing the software, include this License Header Notice in each * file and include the License file at packager/legal/LICENSE.txt. * * GPL Classpath Exception: * Oracle designates this particular file as subject to the "Classpath" * exception as provided by Oracle in the GPL Version 2 section of the License * file that accompanied this code. * * Modifications: * If applicable, add the following below the License Header, with the fields * enclosed by brackets [] replaced by your own identifying information: * "Portions Copyright [year] [name of copyright owner]" * * Contributor(s): * If you wish your version of this file to be governed by only the CDDL or * only the GPL Version 2, indicate your decision by adding "[Contributor] * elects to include this software in this distribution under the [CDDL or GPL * Version 2] license." If you don't indicate a single choice of license, a * recipient has the option to distribute your version of this file under * either the CDDL, the GPL Version 2 or to extend the choice of license to * its licensees as provided above. However, if you add GPL Version 2 code * and therefore, elected the GPL Version 2 license, then the option applies * only if the new code is made subject to such option by the copyright * holder. */ package com.helger.jcodemodel; import java.util.LinkedHashMap; import java.util.Map; import javax.annotation.Nonnull; import javax.annotation.Nullable; import com.helger.jcodemodel.util.JCValueEnforcer; /** * JavaDoc comment. * <p> * A javadoc comment consists of multiple parts. There's the main part (that * comes the first in in the comment section), then the parameter parts * (@param), the return part (@return), and the throws parts (@throws). TODO: it * would be nice if we have JComment class and we can derive this class from * there. */ public class JDocComment extends JCommentPart implements IJGenerable, IJOwned { public static final String TAG_AUTHOR = "author"; public static final String TAG_DEPRECATED = "deprecated"; public static final String TAG_SEE = "see"; public static final String TAG_SINCE = "since"; public static final String TAG_VERSION = "version"; private static final long serialVersionUID = 1L; private final JCodeModel m_aOwner; private boolean m_bIsSingleLineMode = false; /** * list of @param tags */ private final Map <String, JCommentPart> m_aAtParams = new LinkedHashMap <> (); /** * The @return tag part. */ private JCommentPart m_aAtReturn; /** * list of @throws tags */ private final Map <AbstractJClass, JCommentPart> m_aAtThrows = new LinkedHashMap <> (); /** * Other comment tags (like @author, @deprecated, @since, @version etc.) */ private final Map <String, JCommentPart> m_aAtTags = new LinkedHashMap <> (); /** list of generic xdoclets */ private final Map <String, Map <String, String>> m_aAtXdoclets = new LinkedHashMap <> (); protected JDocComment (@Nonnull final JCodeModel owner) { m_aOwner = JCValueEnforcer.notNull (owner, "Owner"); } @Nonnull public JCodeModel owner () { return m_aOwner; } /** * Change whether multi line comments or single line comments should be * emitted. * * @param bSingleLineMode * <code>true</code> to enable single line mode, <code>false</code> for * multi line mode (which is the default). * @return this for chaining */ @Nonnull public JDocComment setSingleLineMode (final boolean bSingleLineMode) { m_bIsSingleLineMode = bSingleLineMode; return this; } /** * @return <code>true</code> if single line mode is enabled, * <code>false</code> if multi line mode is enabled. Multie line mode * is the default. */ public boolean isSingleLineMode () { return m_bIsSingleLineMode; } @Override public JDocComment append (@Nullable final Object o) { add (o); return this; } /** * Append a text to a @param tag to the javadoc * * @param param * Parameter to be added * @return The created {@link JCommentPart} */ @Nonnull public JCommentPart addParam (@Nonnull final String param) { JCommentPart p = m_aAtParams.get (param); if (p == null) { p = new JCommentPart (); m_aAtParams.put (param, p); } return p; } /** * Append a text to an @param tag. * * @param param * Parameter to be added * @return The created {@link JCommentPart} */ public JCommentPart addParam (@Nonnull final JVar param) { return addParam (param.name ()); } @Nullable public JCommentPart removeParam (@Nullable final String param) { return m_aAtParams.remove (param); } @Nullable public JCommentPart removeParam (@Nonnull final JVar param) { return removeParam (param.name ()); } public void removeAllParams () { m_aAtParams.clear (); } @Nullable public JCommentPart getParam (@Nullable final String param) { return m_aAtParams.get (param); } @Nullable public JCommentPart getParam (@Nonnull final JVar param) { return getParam (param.name ()); } /** * Appends a text to @return tag. * * @return Always the same {@link JCommentPart} */ @Nonnull public JCommentPart addReturn () { if (m_aAtReturn == null) m_aAtReturn = new JCommentPart (); return m_aAtReturn; } @Nullable public JCommentPart getReturn () { return m_aAtReturn; } public void removeReturn () { m_aAtReturn = null; } /** * add a @throws tag to the javadoc * * @param exception * Exception to be added. May not be <code>null</code>. * @return New {@link JCommentPart} */ public JCommentPart addThrows (@Nonnull final Class <? extends Throwable> exception) { return addThrows (m_aOwner.ref (exception)); } /** * add a @throws tag to the javadoc * * @param exception * Exception to be added. May not be <code>null</code>. * @return New {@link JCommentPart} */ public JCommentPart addThrows (@Nonnull final AbstractJClass exception) { JCommentPart p = m_aAtThrows.get (exception); if (p == null) { p = new JCommentPart (); m_aAtThrows.put (exception, p); } return p; } @Nullable public JCommentPart removeThrows (@Nonnull final Class <? extends Throwable> exception) { return removeThrows (m_aOwner.ref (exception)); } @Nullable public JCommentPart removeThrows (@Nullable final AbstractJClass exception) { return m_aAtThrows.remove (exception); } public void removeAllThrows () { m_aAtThrows.clear (); } @Nullable public JCommentPart getThrows (@Nonnull final Class <? extends Throwable> exception) { return getThrows (m_aOwner.ref (exception)); } @Nullable public JCommentPart getThrows (@Nullable final AbstractJClass exception) { return m_aAtThrows.get (exception); } @Nonnull public JCommentPart addTag (@Nonnull final String sName) { JCValueEnforcer.notEmpty (sName, "Name"); JCommentPart aPart = m_aAtTags.get (sName); if (aPart == null) { aPart = new JCommentPart (); m_aAtTags.put (sName, aPart); } return aPart; } @Nullable public JCommentPart removeTag (@Nullable final String sName) { return m_aAtTags.remove (sName); } @Nullable public JCommentPart getTag (@Nullable final String sName) { return m_aAtTags.get (sName); } /** * Create an @author tag. * * @return Always the same {@link JCommentPart} * @see #addTag(String) */ @Nonnull public JCommentPart addAuthor () { return addTag (TAG_AUTHOR); } public void removeAuthor () { removeTag (TAG_AUTHOR); } /** * add a @deprecated tag to the javadoc, with the associated message. * * @return Always the same {@link JCommentPart} * @see #addTag(String) */ @Nonnull public JCommentPart addDeprecated () { return addTag (TAG_DEPRECATED); } public void removeDeprecated () { removeTag (TAG_DEPRECATED); } /** * add an xdoclet. * * @param name * xdoclet name * @return Map with the key/value pairs */ @Nonnull public Map <String, String> addXdoclet (@Nonnull final String name) { Map <String, String> p = m_aAtXdoclets.get (name); if (p == null) { p = new LinkedHashMap <> (); m_aAtXdoclets.put (name, p); } return p; } /** * add an xdoclet. * * @param name * xdoclet name * @param attributes * Attributes to be added * @return Map with the key/value pairs */ @Nonnull public Map <String, String> addXdoclet (@Nonnull final String name, @Nonnull final Map <String, String> attributes) { final Map <String, String> p = addXdoclet (name); p.putAll (attributes); return p; } /** * add an xdoclet with <code>@name attribute = "value"</code>. If value is * <code>null</code> than it will be <code>@name attribute</code>. * * @param name * xdoclet name * @param attribute * Attribute name to be added * @param value * Attribute value to be added * @return Map with the key/value pairs */ @Nonnull public Map <String, String> addXdoclet (@Nonnull final String name, @Nonnull final String attribute, @Nullable final String value) { final Map <String, String> p = addXdoclet (name); p.put (attribute, value); return p; } @Nullable public Map <String, String> removeXdoclet (@Nullable final String name) { return m_aAtXdoclets.remove (name); } public void removeAllXdoclets () { m_aAtXdoclets.clear (); } public void generate (@Nonnull final JFormatter f) { // Is any "@" comment present? final boolean bHasAt = !m_aAtParams.isEmpty () || m_aAtReturn != null || !m_aAtThrows.isEmpty () || !m_aAtTags.isEmpty () || !m_aAtXdoclets.isEmpty (); if (!isEmpty () || bHasAt) { final boolean bIsJavaDoc = true; final String sIndent = m_bIsSingleLineMode ? "// " : " * "; final String sIndentLarge = sIndent + " "; // Start comment if (!m_bIsSingleLineMode) f.print (bIsJavaDoc ? "/**" : "/*").newline (); // Print all simple text elements format (f, sIndent); if (!isEmpty () && bHasAt) f.print (sIndent).newline (); for (final Map.Entry <String, JCommentPart> aEntry : m_aAtParams.entrySet ()) { f.print (sIndent + "@param ").print (aEntry.getKey ()).newline (); aEntry.getValue ().format (f, sIndentLarge); } if (m_aAtReturn != null) { f.print (sIndent + "@return").newline (); m_aAtReturn.format (f, sIndentLarge); } for (final Map.Entry <AbstractJClass, JCommentPart> aEntry : m_aAtThrows.entrySet ()) { f.print (sIndent + "@throws ").type (aEntry.getKey ()).newline (); aEntry.getValue ().format (f, sIndentLarge); } for (final Map.Entry <String, JCommentPart> aEntry : m_aAtTags.entrySet ()) { f.print (sIndent + "@" + aEntry.getKey () + " "); aEntry.getValue ().format (f, ""); } for (final Map.Entry <String, Map <String, String>> aEntry : m_aAtXdoclets.entrySet ()) { f.print (sIndent + "@").print (aEntry.getKey ()); if (aEntry.getValue () != null) { for (final Map.Entry <String, String> aEntry2 : aEntry.getValue ().entrySet ()) { final String sName = aEntry2.getKey (); f.print (" ").print (sName); // Print value only if present final String sValue = aEntry2.getValue (); if (sValue != null && sValue.length () > 0) f.print ("= \"").print (sValue).print ("\""); } } f.newline (); } // End comment if (!m_bIsSingleLineMode) f.print (" */").newline (); } } }