Splits tag generated html into description and attributes
diff --git a/.gitignore b/.gitignore
index 987f5a6..e5b4e74 100644
--- a/.gitignore
+++ b/.gitignore
@@ -8,3 +8,6 @@
*.ipr
*.iws
*.iml
+
+# Maven
+target/
diff --git a/.mvn/wrapper/MavenWrapperDownloader.java b/.mvn/wrapper/MavenWrapperDownloader.java
new file mode 100644
index 0000000..c32394f
--- /dev/null
+++ b/.mvn/wrapper/MavenWrapperDownloader.java
@@ -0,0 +1,117 @@
+/*
+ * Copyright 2007-present the original author or authors.
+ *
+ * Licensed 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 java.net.*;
+import java.io.*;
+import java.nio.channels.*;
+import java.util.Properties;
+
+public class MavenWrapperDownloader {
+
+ private static final String WRAPPER_VERSION = "0.5.5";
+ /**
+ * Default URL to download the maven-wrapper.jar from, if no 'downloadUrl' is provided.
+ */
+ private static final String DEFAULT_DOWNLOAD_URL = "https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/"
+ + WRAPPER_VERSION + "/maven-wrapper-" + WRAPPER_VERSION + ".jar";
+
+ /**
+ * Path to the maven-wrapper.properties file, which might contain a downloadUrl property to
+ * use instead of the default one.
+ */
+ private static final String MAVEN_WRAPPER_PROPERTIES_PATH =
+ ".mvn/wrapper/maven-wrapper.properties";
+
+ /**
+ * Path where the maven-wrapper.jar will be saved to.
+ */
+ private static final String MAVEN_WRAPPER_JAR_PATH =
+ ".mvn/wrapper/maven-wrapper.jar";
+
+ /**
+ * Name of the property which should be used to override the default download url for the wrapper.
+ */
+ private static final String PROPERTY_NAME_WRAPPER_URL = "wrapperUrl";
+
+ public static void main(String args[]) {
+ System.out.println("- Downloader started");
+ File baseDirectory = new File(args[0]);
+ System.out.println("- Using base directory: " + baseDirectory.getAbsolutePath());
+
+ // If the maven-wrapper.properties exists, read it and check if it contains a custom
+ // wrapperUrl parameter.
+ File mavenWrapperPropertyFile = new File(baseDirectory, MAVEN_WRAPPER_PROPERTIES_PATH);
+ String url = DEFAULT_DOWNLOAD_URL;
+ if(mavenWrapperPropertyFile.exists()) {
+ FileInputStream mavenWrapperPropertyFileInputStream = null;
+ try {
+ mavenWrapperPropertyFileInputStream = new FileInputStream(mavenWrapperPropertyFile);
+ Properties mavenWrapperProperties = new Properties();
+ mavenWrapperProperties.load(mavenWrapperPropertyFileInputStream);
+ url = mavenWrapperProperties.getProperty(PROPERTY_NAME_WRAPPER_URL, url);
+ } catch (IOException e) {
+ System.out.println("- ERROR loading '" + MAVEN_WRAPPER_PROPERTIES_PATH + "'");
+ } finally {
+ try {
+ if(mavenWrapperPropertyFileInputStream != null) {
+ mavenWrapperPropertyFileInputStream.close();
+ }
+ } catch (IOException e) {
+ // Ignore ...
+ }
+ }
+ }
+ System.out.println("- Downloading from: " + url);
+
+ File outputFile = new File(baseDirectory.getAbsolutePath(), MAVEN_WRAPPER_JAR_PATH);
+ if(!outputFile.getParentFile().exists()) {
+ if(!outputFile.getParentFile().mkdirs()) {
+ System.out.println(
+ "- ERROR creating output directory '" + outputFile.getParentFile().getAbsolutePath() + "'");
+ }
+ }
+ System.out.println("- Downloading to: " + outputFile.getAbsolutePath());
+ try {
+ downloadFileFromURL(url, outputFile);
+ System.out.println("Done");
+ System.exit(0);
+ } catch (Throwable e) {
+ System.out.println("- Error downloading");
+ e.printStackTrace();
+ System.exit(1);
+ }
+ }
+
+ private static void downloadFileFromURL(String urlString, File destination) throws Exception {
+ if (System.getenv("MVNW_USERNAME") != null && System.getenv("MVNW_PASSWORD") != null) {
+ String username = System.getenv("MVNW_USERNAME");
+ char[] password = System.getenv("MVNW_PASSWORD").toCharArray();
+ Authenticator.setDefault(new Authenticator() {
+ @Override
+ protected PasswordAuthentication getPasswordAuthentication() {
+ return new PasswordAuthentication(username, password);
+ }
+ });
+ }
+ URL website = new URL(urlString);
+ ReadableByteChannel rbc;
+ rbc = Channels.newChannel(website.openStream());
+ FileOutputStream fos = new FileOutputStream(destination);
+ fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE);
+ fos.close();
+ rbc.close();
+ }
+
+}
diff --git a/.mvn/wrapper/maven-wrapper.jar b/.mvn/wrapper/maven-wrapper.jar
new file mode 100644
index 0000000..0d5e649
--- /dev/null
+++ b/.mvn/wrapper/maven-wrapper.jar
Binary files differ
diff --git a/.mvn/wrapper/maven-wrapper.properties b/.mvn/wrapper/maven-wrapper.properties
new file mode 100644
index 0000000..fa87ad7
--- /dev/null
+++ b/.mvn/wrapper/maven-wrapper.properties
@@ -0,0 +1,2 @@
+distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.1/apache-maven-3.6.1-bin.zip
+wrapperUrl=https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.5/maven-wrapper-0.5.5.jar
diff --git a/mvnw b/mvnw
new file mode 100755
index 0000000..d2f0ea3
--- /dev/null
+++ b/mvnw
@@ -0,0 +1,310 @@
+#!/bin/sh
+# ----------------------------------------------------------------------------
+# 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.
+# ----------------------------------------------------------------------------
+
+# ----------------------------------------------------------------------------
+# Maven2 Start Up Batch script
+#
+# Required ENV vars:
+# ------------------
+# JAVA_HOME - location of a JDK home dir
+#
+# Optional ENV vars
+# -----------------
+# M2_HOME - location of maven2's installed home dir
+# MAVEN_OPTS - parameters passed to the Java VM when running Maven
+# e.g. to debug Maven itself, use
+# set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
+# MAVEN_SKIP_RC - flag to disable loading of mavenrc files
+# ----------------------------------------------------------------------------
+
+if [ -z "$MAVEN_SKIP_RC" ] ; then
+
+ if [ -f /etc/mavenrc ] ; then
+ . /etc/mavenrc
+ fi
+
+ if [ -f "$HOME/.mavenrc" ] ; then
+ . "$HOME/.mavenrc"
+ fi
+
+fi
+
+# OS specific support. $var _must_ be set to either true or false.
+cygwin=false;
+darwin=false;
+mingw=false
+case "`uname`" in
+ CYGWIN*) cygwin=true ;;
+ MINGW*) mingw=true;;
+ Darwin*) darwin=true
+ # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home
+ # See https://developer.apple.com/library/mac/qa/qa1170/_index.html
+ if [ -z "$JAVA_HOME" ]; then
+ if [ -x "/usr/libexec/java_home" ]; then
+ export JAVA_HOME="`/usr/libexec/java_home`"
+ else
+ export JAVA_HOME="/Library/Java/Home"
+ fi
+ fi
+ ;;
+esac
+
+if [ -z "$JAVA_HOME" ] ; then
+ if [ -r /etc/gentoo-release ] ; then
+ JAVA_HOME=`java-config --jre-home`
+ fi
+fi
+
+if [ -z "$M2_HOME" ] ; then
+ ## resolve links - $0 may be a link to maven's home
+ PRG="$0"
+
+ # need this for relative symlinks
+ while [ -h "$PRG" ] ; do
+ ls=`ls -ld "$PRG"`
+ link=`expr "$ls" : '.*-> \(.*\)$'`
+ if expr "$link" : '/.*' > /dev/null; then
+ PRG="$link"
+ else
+ PRG="`dirname "$PRG"`/$link"
+ fi
+ done
+
+ saveddir=`pwd`
+
+ M2_HOME=`dirname "$PRG"`/..
+
+ # make it fully qualified
+ M2_HOME=`cd "$M2_HOME" && pwd`
+
+ cd "$saveddir"
+ # echo Using m2 at $M2_HOME
+fi
+
+# For Cygwin, ensure paths are in UNIX format before anything is touched
+if $cygwin ; then
+ [ -n "$M2_HOME" ] &&
+ M2_HOME=`cygpath --unix "$M2_HOME"`
+ [ -n "$JAVA_HOME" ] &&
+ JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
+ [ -n "$CLASSPATH" ] &&
+ CLASSPATH=`cygpath --path --unix "$CLASSPATH"`
+fi
+
+# For Mingw, ensure paths are in UNIX format before anything is touched
+if $mingw ; then
+ [ -n "$M2_HOME" ] &&
+ M2_HOME="`(cd "$M2_HOME"; pwd)`"
+ [ -n "$JAVA_HOME" ] &&
+ JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`"
+fi
+
+if [ -z "$JAVA_HOME" ]; then
+ javaExecutable="`which javac`"
+ if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then
+ # readlink(1) is not available as standard on Solaris 10.
+ readLink=`which readlink`
+ if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then
+ if $darwin ; then
+ javaHome="`dirname \"$javaExecutable\"`"
+ javaExecutable="`cd \"$javaHome\" && pwd -P`/javac"
+ else
+ javaExecutable="`readlink -f \"$javaExecutable\"`"
+ fi
+ javaHome="`dirname \"$javaExecutable\"`"
+ javaHome=`expr "$javaHome" : '\(.*\)/bin'`
+ JAVA_HOME="$javaHome"
+ export JAVA_HOME
+ fi
+ fi
+fi
+
+if [ -z "$JAVACMD" ] ; then
+ if [ -n "$JAVA_HOME" ] ; then
+ if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+ # IBM's JDK on AIX uses strange locations for the executables
+ JAVACMD="$JAVA_HOME/jre/sh/java"
+ else
+ JAVACMD="$JAVA_HOME/bin/java"
+ fi
+ else
+ JAVACMD="`which java`"
+ fi
+fi
+
+if [ ! -x "$JAVACMD" ] ; then
+ echo "Error: JAVA_HOME is not defined correctly." >&2
+ echo " We cannot execute $JAVACMD" >&2
+ exit 1
+fi
+
+if [ -z "$JAVA_HOME" ] ; then
+ echo "Warning: JAVA_HOME environment variable is not set."
+fi
+
+CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher
+
+# traverses directory structure from process work directory to filesystem root
+# first directory with .mvn subdirectory is considered project base directory
+find_maven_basedir() {
+
+ if [ -z "$1" ]
+ then
+ echo "Path not specified to find_maven_basedir"
+ return 1
+ fi
+
+ basedir="$1"
+ wdir="$1"
+ while [ "$wdir" != '/' ] ; do
+ if [ -d "$wdir"/.mvn ] ; then
+ basedir=$wdir
+ break
+ fi
+ # workaround for JBEAP-8937 (on Solaris 10/Sparc)
+ if [ -d "${wdir}" ]; then
+ wdir=`cd "$wdir/.."; pwd`
+ fi
+ # end of workaround
+ done
+ echo "${basedir}"
+}
+
+# concatenates all lines of a file
+concat_lines() {
+ if [ -f "$1" ]; then
+ echo "$(tr -s '\n' ' ' < "$1")"
+ fi
+}
+
+BASE_DIR=`find_maven_basedir "$(pwd)"`
+if [ -z "$BASE_DIR" ]; then
+ exit 1;
+fi
+
+##########################################################################################
+# Extension to allow automatically downloading the maven-wrapper.jar from Maven-central
+# This allows using the maven wrapper in projects that prohibit checking in binary data.
+##########################################################################################
+if [ -r "$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" ]; then
+ if [ "$MVNW_VERBOSE" = true ]; then
+ echo "Found .mvn/wrapper/maven-wrapper.jar"
+ fi
+else
+ if [ "$MVNW_VERBOSE" = true ]; then
+ echo "Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ..."
+ fi
+ if [ -n "$MVNW_REPOURL" ]; then
+ jarUrl="$MVNW_REPOURL/io/takari/maven-wrapper/0.5.5/maven-wrapper-0.5.5.jar"
+ else
+ jarUrl="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.5/maven-wrapper-0.5.5.jar"
+ fi
+ while IFS="=" read key value; do
+ case "$key" in (wrapperUrl) jarUrl="$value"; break ;;
+ esac
+ done < "$BASE_DIR/.mvn/wrapper/maven-wrapper.properties"
+ if [ "$MVNW_VERBOSE" = true ]; then
+ echo "Downloading from: $jarUrl"
+ fi
+ wrapperJarPath="$BASE_DIR/.mvn/wrapper/maven-wrapper.jar"
+ if $cygwin; then
+ wrapperJarPath=`cygpath --path --windows "$wrapperJarPath"`
+ fi
+
+ if command -v wget > /dev/null; then
+ if [ "$MVNW_VERBOSE" = true ]; then
+ echo "Found wget ... using wget"
+ fi
+ if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then
+ wget "$jarUrl" -O "$wrapperJarPath"
+ else
+ wget --http-user=$MVNW_USERNAME --http-password=$MVNW_PASSWORD "$jarUrl" -O "$wrapperJarPath"
+ fi
+ elif command -v curl > /dev/null; then
+ if [ "$MVNW_VERBOSE" = true ]; then
+ echo "Found curl ... using curl"
+ fi
+ if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then
+ curl -o "$wrapperJarPath" "$jarUrl" -f
+ else
+ curl --user $MVNW_USERNAME:$MVNW_PASSWORD -o "$wrapperJarPath" "$jarUrl" -f
+ fi
+
+ else
+ if [ "$MVNW_VERBOSE" = true ]; then
+ echo "Falling back to using Java to download"
+ fi
+ javaClass="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java"
+ # For Cygwin, switch paths to Windows format before running javac
+ if $cygwin; then
+ javaClass=`cygpath --path --windows "$javaClass"`
+ fi
+ if [ -e "$javaClass" ]; then
+ if [ ! -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then
+ if [ "$MVNW_VERBOSE" = true ]; then
+ echo " - Compiling MavenWrapperDownloader.java ..."
+ fi
+ # Compiling the Java class
+ ("$JAVA_HOME/bin/javac" "$javaClass")
+ fi
+ if [ -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then
+ # Running the downloader
+ if [ "$MVNW_VERBOSE" = true ]; then
+ echo " - Running MavenWrapperDownloader.java ..."
+ fi
+ ("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$MAVEN_PROJECTBASEDIR")
+ fi
+ fi
+ fi
+fi
+##########################################################################################
+# End of extension
+##########################################################################################
+
+export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"}
+if [ "$MVNW_VERBOSE" = true ]; then
+ echo $MAVEN_PROJECTBASEDIR
+fi
+MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS"
+
+# For Cygwin, switch paths to Windows format before running java
+if $cygwin; then
+ [ -n "$M2_HOME" ] &&
+ M2_HOME=`cygpath --path --windows "$M2_HOME"`
+ [ -n "$JAVA_HOME" ] &&
+ JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"`
+ [ -n "$CLASSPATH" ] &&
+ CLASSPATH=`cygpath --path --windows "$CLASSPATH"`
+ [ -n "$MAVEN_PROJECTBASEDIR" ] &&
+ MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"`
+fi
+
+# Provide a "standardized" way to retrieve the CLI args that will
+# work with both Windows and non-Windows executions.
+MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $@"
+export MAVEN_CMD_LINE_ARGS
+
+WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
+
+exec "$JAVACMD" \
+ $MAVEN_OPTS \
+ -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \
+ "-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \
+ ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@"
diff --git a/mvnw.cmd b/mvnw.cmd
new file mode 100644
index 0000000..b26ab24
--- /dev/null
+++ b/mvnw.cmd
@@ -0,0 +1,182 @@
+@REM ----------------------------------------------------------------------------
+@REM Licensed to the Apache Software Foundation (ASF) under one
+@REM or more contributor license agreements. See the NOTICE file
+@REM distributed with this work for additional information
+@REM regarding copyright ownership. The ASF licenses this file
+@REM to you under the Apache License, Version 2.0 (the
+@REM "License"); you may not use this file except in compliance
+@REM with the License. You may obtain a copy of the License at
+@REM
+@REM http://www.apache.org/licenses/LICENSE-2.0
+@REM
+@REM Unless required by applicable law or agreed to in writing,
+@REM software distributed under the License is distributed on an
+@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+@REM KIND, either express or implied. See the License for the
+@REM specific language governing permissions and limitations
+@REM under the License.
+@REM ----------------------------------------------------------------------------
+
+@REM ----------------------------------------------------------------------------
+@REM Maven2 Start Up Batch script
+@REM
+@REM Required ENV vars:
+@REM JAVA_HOME - location of a JDK home dir
+@REM
+@REM Optional ENV vars
+@REM M2_HOME - location of maven2's installed home dir
+@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands
+@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a key stroke before ending
+@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven
+@REM e.g. to debug Maven itself, use
+@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
+@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files
+@REM ----------------------------------------------------------------------------
+
+@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on'
+@echo off
+@REM set title of command window
+title %0
+@REM enable echoing by setting MAVEN_BATCH_ECHO to 'on'
+@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO%
+
+@REM set %HOME% to equivalent of $HOME
+if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%")
+
+@REM Execute a user defined script before this one
+if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre
+@REM check for pre script, once with legacy .bat ending and once with .cmd ending
+if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat"
+if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd"
+:skipRcPre
+
+@setlocal
+
+set ERROR_CODE=0
+
+@REM To isolate internal variables from possible post scripts, we use another setlocal
+@setlocal
+
+@REM ==== START VALIDATION ====
+if not "%JAVA_HOME%" == "" goto OkJHome
+
+echo.
+echo Error: JAVA_HOME not found in your environment. >&2
+echo Please set the JAVA_HOME variable in your environment to match the >&2
+echo location of your Java installation. >&2
+echo.
+goto error
+
+:OkJHome
+if exist "%JAVA_HOME%\bin\java.exe" goto init
+
+echo.
+echo Error: JAVA_HOME is set to an invalid directory. >&2
+echo JAVA_HOME = "%JAVA_HOME%" >&2
+echo Please set the JAVA_HOME variable in your environment to match the >&2
+echo location of your Java installation. >&2
+echo.
+goto error
+
+@REM ==== END VALIDATION ====
+
+:init
+
+@REM Find the project base dir, i.e. the directory that contains the folder ".mvn".
+@REM Fallback to current working directory if not found.
+
+set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR%
+IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir
+
+set EXEC_DIR=%CD%
+set WDIR=%EXEC_DIR%
+:findBaseDir
+IF EXIST "%WDIR%"\.mvn goto baseDirFound
+cd ..
+IF "%WDIR%"=="%CD%" goto baseDirNotFound
+set WDIR=%CD%
+goto findBaseDir
+
+:baseDirFound
+set MAVEN_PROJECTBASEDIR=%WDIR%
+cd "%EXEC_DIR%"
+goto endDetectBaseDir
+
+:baseDirNotFound
+set MAVEN_PROJECTBASEDIR=%EXEC_DIR%
+cd "%EXEC_DIR%"
+
+:endDetectBaseDir
+
+IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig
+
+@setlocal EnableExtensions EnableDelayedExpansion
+for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a
+@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS%
+
+:endReadAdditionalConfig
+
+SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe"
+set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar"
+set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
+
+set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.5/maven-wrapper-0.5.5.jar"
+
+FOR /F "tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO (
+ IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B
+)
+
+@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central
+@REM This allows using the maven wrapper in projects that prohibit checking in binary data.
+if exist %WRAPPER_JAR% (
+ if "%MVNW_VERBOSE%" == "true" (
+ echo Found %WRAPPER_JAR%
+ )
+) else (
+ if not "%MVNW_REPOURL%" == "" (
+ SET DOWNLOAD_URL="%MVNW_REPOURL%/io/takari/maven-wrapper/0.5.5/maven-wrapper-0.5.5.jar"
+ )
+ if "%MVNW_VERBOSE%" == "true" (
+ echo Couldn't find %WRAPPER_JAR%, downloading it ...
+ echo Downloading from: %DOWNLOAD_URL%
+ )
+
+ powershell -Command "&{"^
+ "$webclient = new-object System.Net.WebClient;"^
+ "if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^
+ "$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^
+ "}"^
+ "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')"^
+ "}"
+ if "%MVNW_VERBOSE%" == "true" (
+ echo Finished downloading %WRAPPER_JAR%
+ )
+)
+@REM End of extension
+
+@REM Provide a "standardized" way to retrieve the CLI args that will
+@REM work with both Windows and non-Windows executions.
+set MAVEN_CMD_LINE_ARGS=%*
+
+%MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %*
+if ERRORLEVEL 1 goto error
+goto end
+
+:error
+set ERROR_CODE=1
+
+:end
+@endlocal & set ERROR_CODE=%ERROR_CODE%
+
+if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost
+@REM check for post script, once with legacy .bat ending and once with .cmd ending
+if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat"
+if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd"
+:skipRcPost
+
+@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on'
+if "%MAVEN_BATCH_PAUSE%" == "on" pause
+
+if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE%
+
+exit /B %ERROR_CODE%
diff --git a/pom.xml b/pom.xml
index 800198e..48580f3 100644
--- a/pom.xml
+++ b/pom.xml
@@ -1,92 +1,63 @@
-<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">
+<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">
- <parent>
- <groupId>org.apache.struts</groupId>
- <artifactId>struts-master</artifactId>
- <version>9</version>
- </parent>
+ <parent>
+ <groupId>org.apache.struts</groupId>
+ <artifactId>struts-master</artifactId>
+ <version>14</version>
+ </parent>
- <modelVersion>4.0.0</modelVersion>
- <artifactId>struts-annotations</artifactId>
- <version>1.0.7-SNAPSHOT</version>
- <packaging>jar</packaging>
- <name>Struts Annotations</name>
- <url>http://struts.apache.org</url>
- <description>
- struts-annotations adds annotations processor support for struts based annotated projects,
- such as TLD and documentation generation from annotated component classes as used in struts2
- </description>
+ <modelVersion>4.0.0</modelVersion>
+ <artifactId>struts-annotations</artifactId>
+ <version>1.0.7-SNAPSHOT</version>
+ <packaging>jar</packaging>
+ <name>Struts Annotations</name>
+ <url>http://struts.apache.org</url>
+ <description>
+ struts-annotations adds annotations processor support for struts based annotated projects,
+ such as TLD and documentation generation from annotated component classes as used in struts2
+ </description>
- <scm>
- <connection>scm:git:git://git.apache.org/struts-annotations.git</connection>
- <developerConnection>scm:git:https://git-wip-us.apache.org/repos/asf/struts-annotations.git</developerConnection>
- <url>http://git.apache.org/struts-annotations.git</url>
- <tag>HEAD</tag>
- </scm>
+ <scm>
+ <connection>scm:git:git://git.apache.org/struts-annotations.git</connection>
+ <developerConnection>scm:git:https://git-wip-us.apache.org/repos/asf/struts-annotations.git
+ </developerConnection>
+ <url>http://git.apache.org/struts-annotations.git</url>
+ <tag>HEAD</tag>
+ </scm>
- <properties>
- <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
- </properties>
+ <properties>
+ <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+ <freemarker.version>2.3.29</freemarker.version>
+ <java.version>1.8</java.version>
+ </properties>
- <build>
+ <build>
- <pluginManagement>
- <plugins>
- <plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-release-plugin</artifactId>
- <version>2.5</version>
- </plugin>
- </plugins>
- </pluginManagement>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-release-plugin</artifactId>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <configuration>
+ <source>${java.version}</source>
+ <target>${java.version}</target>
+ <compilerArgument>-proc:none</compilerArgument>
+ </configuration>
+ </plugin>
+ </plugins>
- <plugins>
- <plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-release-plugin</artifactId>
- <version>2.5</version>
- </plugin>
- <plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-compiler-plugin</artifactId>
- <version>3.3</version>
- <configuration>
- <source>1.7</source>
- <target>1.7</target>
- <compilerArgument>-proc:none</compilerArgument>
- </configuration>
- </plugin>
- </plugins>
+ </build>
- </build>
-
- <profiles>
- <profile>
- <id>default-tools.jar</id>
- <activation>
- <property>
- <name>java.vendor</name>
- <value>Sun Microsystems Inc.</value>
- </property>
- </activation>
- <dependencies>
+ <dependencies>
<dependency>
- <groupId>com.sun</groupId>
- <artifactId>tools</artifactId>
- <version>1.7.0</version>
- <scope>system</scope>
- <systemPath>${java.home}/../lib/tools.jar</systemPath>
+ <groupId>org.freemarker</groupId>
+ <artifactId>freemarker</artifactId>
+ <version>${freemarker.version}</version>
</dependency>
- </dependencies>
- </profile>
- </profiles>
-
- <dependencies>
- <dependency>
- <groupId>org.freemarker</groupId>
- <artifactId>freemarker</artifactId>
- <version>2.3.11</version>
- </dependency>
- </dependencies>
+ </dependencies>
</project>
diff --git a/src/main/java/org/apache/struts/annotations/taglib/apt/TagAnnotationProcessor.java b/src/main/java/org/apache/struts/annotations/taglib/apt/TagAnnotationProcessor.java
index 7134291..1e23b66 100644
--- a/src/main/java/org/apache/struts/annotations/taglib/apt/TagAnnotationProcessor.java
+++ b/src/main/java/org/apache/struts/annotations/taglib/apt/TagAnnotationProcessor.java
@@ -20,47 +20,31 @@
*/
package org.apache.struts.annotations.taglib.apt;
-import java.io.BufferedWriter;
-import java.io.File;
-import java.io.FileOutputStream;
-import java.io.FileWriter;
-import java.io.OutputStreamWriter;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.Set;
-import java.util.TreeMap;
-
-import javax.annotation.processing.AbstractProcessor;
-import javax.annotation.processing.RoundEnvironment;
-import javax.annotation.processing.SupportedAnnotationTypes;
-import javax.lang.model.element.AnnotationMirror;
-import javax.lang.model.element.AnnotationValue;
-import javax.lang.model.element.ExecutableElement;
-import javax.lang.model.element.Modifier;
-import javax.lang.model.element.TypeElement;
-import javax.lang.model.type.NoType;
-import javax.lang.model.util.ElementFilter;
-import javax.xml.parsers.DocumentBuilder;
-import javax.xml.parsers.DocumentBuilderFactory;
-import javax.xml.transform.OutputKeys;
-import javax.xml.transform.Result;
-import javax.xml.transform.Source;
-import javax.xml.transform.Transformer;
-import javax.xml.transform.TransformerFactory;
-import javax.xml.transform.dom.DOMSource;
-import javax.xml.transform.stream.StreamResult;
-
+import freemarker.template.Configuration;
+import freemarker.template.DefaultObjectWrapper;
+import freemarker.template.Template;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Text;
-import freemarker.template.Configuration;
-import freemarker.template.DefaultObjectWrapper;
-import freemarker.template.Template;
+import javax.annotation.processing.AbstractProcessor;
+import javax.annotation.processing.RoundEnvironment;
+import javax.annotation.processing.SupportedAnnotationTypes;
+import javax.annotation.processing.SupportedSourceVersion;
+import javax.lang.model.SourceVersion;
+import javax.lang.model.element.*;
+import javax.lang.model.type.NoType;
+import javax.lang.model.util.ElementFilter;
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.transform.*;
+import javax.xml.transform.dom.DOMSource;
+import javax.xml.transform.stream.StreamResult;
+import java.io.*;
+import java.util.*;
+import java.util.Map.Entry;
+@SupportedSourceVersion(SourceVersion.RELEASE_8)
@SupportedAnnotationTypes({TagAnnotationProcessor.TAG, TagAnnotationProcessor.TAG_ATTRIBUTE, TagAnnotationProcessor.TAG_SKIP_HIERARCHY})
public class TagAnnotationProcessor extends AbstractProcessor {
public static final String TAG = "org.apache.struts2.views.annotations.StrutsTag";
@@ -70,7 +54,7 @@
private Map<String, Tag> tags = new TreeMap<>();
@Override
- public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
+ public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
// make sure all paramters were set
checkOptions();
@@ -78,15 +62,15 @@
TypeElement tagAnnotationType = processingEnv.getElementUtils().getTypeElement(TAG);
TypeElement attributeAnnotationType = processingEnv.getElementUtils().getTypeElement(TAG_ATTRIBUTE);
TypeElement skipAnnotationType = processingEnv.getElementUtils().getTypeElement(TAG_SKIP_HIERARCHY);
- Set<? extends javax.lang.model.element.Element> tagDeclarations = roundEnv.getElementsAnnotatedWith(tagAnnotationType);
- Set<? extends javax.lang.model.element.Element> attributesDeclarations = roundEnv.getElementsAnnotatedWith(attributeAnnotationType);
- Set<? extends javax.lang.model.element.Element> skipDeclarations = roundEnv.getElementsAnnotatedWith(skipAnnotationType);
+ Set<? extends javax.lang.model.element.Element> tagDeclarations = roundEnv.getElementsAnnotatedWith(tagAnnotationType);
+ Set<? extends javax.lang.model.element.Element> attributesDeclarations = roundEnv.getElementsAnnotatedWith(attributeAnnotationType);
+ Set<? extends javax.lang.model.element.Element> skipDeclarations = roundEnv.getElementsAnnotatedWith(skipAnnotationType);
// find Tags
- for (javax.lang.model.element.Element element : tagDeclarations) {
- Map<String, Object> values = getValues(element, tagAnnotationType);
- TypeElement type = (TypeElement) element;
- Tag tag = new Tag();
+ for (javax.lang.model.element.Element element : tagDeclarations) {
+ Map<String, Object> values = getValues(element, tagAnnotationType);
+ TypeElement type = (TypeElement) element;
+ Tag tag = new Tag();
tag.setDescription((String) values.get("description"));
tag.setName((String) values.get("name"));
tag.setTldBodyContent((String) values.get("tldBodyContent"));
@@ -95,20 +79,18 @@
tag.setAllowDynamicAttributes((Boolean) values.get("allowDynamicAttributes"));
// add to map
tags.put(type.getQualifiedName().toString(), tag);
- }
+ }
//find attributes to be skipped
for (javax.lang.model.element.Element declaration : skipDeclarations) {
//types will be ignored when hierarchy is scanned
if (declaration instanceof ExecutableElement) {
- ExecutableElement methodDeclaration = (ExecutableElement) declaration;
+ ExecutableElement methodDeclaration = (ExecutableElement) declaration;
String typeName = ((TypeElement) methodDeclaration.getEnclosingElement()).getQualifiedName().toString();
String methodName = methodDeclaration.getSimpleName().toString();
- String name = String.valueOf(Character.toLowerCase(methodName
- .charAt(3)))
- + methodName.substring(4);
+ String name = Character.toLowerCase(methodName.charAt(3)) + methodName.substring(4);
Tag tag = tags.get(typeName);
- if(tag != null) {
+ if (tag != null) {
//if it is on an abstract class, there is not tag for it at this point
tags.get(typeName).addSkipAttribute(name);
}
@@ -118,8 +100,8 @@
// find Tags Attributes
for (javax.lang.model.element.Element declaration : attributesDeclarations) {
// type
- ExecutableElement methodDeclaration = (ExecutableElement) declaration;
- String typeName = ((TypeElement) methodDeclaration.getEnclosingElement()).getQualifiedName().toString();
+ ExecutableElement methodDeclaration = (ExecutableElement) declaration;
+ String typeName = ((TypeElement) methodDeclaration.getEnclosingElement()).getQualifiedName().toString();
Map<String, Object> values = getValues(methodDeclaration,
attributeAnnotationType);
// create Attribute and apply values found
@@ -128,17 +110,15 @@
if (name == null || name.length() == 0) {
// get name from method
String methodName = methodDeclaration.getSimpleName().toString();
- name = String.valueOf(Character.toLowerCase(methodName
- .charAt(3)))
- + methodName.substring(4);
+ name = Character.toLowerCase(methodName.charAt(3)) + methodName.substring(4);
}
values.put("name", name);
populateTagAttributes(attribute, values);
// add to map
Tag parentTag = tags.get(typeName);
- if (parentTag != null){
+ if (parentTag != null) {
tags.get(typeName).addTagAttribute(attribute);
- }else {
+ } else {
// an abstract or base class
parentTag = new Tag();
parentTag.setDeclaredType(typeName);
@@ -171,14 +151,14 @@
}
private void processHierarchy(Tag tag) {
- TypeElement type = processingEnv.getElementUtils().getTypeElement(tag.getDeclaredType());
- List<String> skipAttributes = tag.getSkipAttributes();
- while (type !=null && !(type instanceof NoType) && getAnnotation(type, TAG_SKIP_HIERARCHY) == null) {
- Tag parentTag = tags.get(type.getQualifiedName().toString());
+ TypeElement type = processingEnv.getElementUtils().getTypeElement(tag.getDeclaredType());
+ List<String> skipAttributes = tag.getSkipAttributes();
+ while (type != null && !(type instanceof NoType) && getAnnotation(type, TAG_SKIP_HIERARCHY) == null) {
+ Tag parentTag = tags.get(type.getQualifiedName().toString());
// copy parent annotations to this tag
- if(parentTag != null) {
- for(TagAttribute attribute : parentTag.getAttributes()) {
- if(!skipAttributes.contains(attribute.getName())){
+ if (parentTag != null) {
+ for (TagAttribute attribute : parentTag.getAttributes()) {
+ if (!skipAttributes.contains(attribute.getName())) {
tag.addTagAttribute(attribute);
}
}
@@ -187,39 +167,39 @@
addTagAttributesFromParent(tag, type);
}
type = (TypeElement) processingEnv.getTypeUtils().asElement(type.getSuperclass());
- }
+ }
}
private void addTagAttributesFromParent(Tag tag, TypeElement type) {
- for (ExecutableElement method : ElementFilter.methodsIn(processingEnv.getElementUtils().getAllMembers(type))) {
- AnnotationMirror annotation = getAnnotation(method, TAG_ATTRIBUTE);
- if (method.getModifiers().contains(Modifier.PUBLIC) && annotation != null) {
- String name = String.valueOf(Character.toLowerCase(method.getSimpleName()
- .charAt(3)))
- + method.getSimpleName().subSequence(4, method.getSimpleName().length());
- if (!tag.getSkipAttributes().contains(name)) {
- Map<String, Object> values = new HashMap<>();
- for (Entry<? extends ExecutableElement, ? extends AnnotationValue> entry : processingEnv.getElementUtils().getElementValuesWithDefaults(annotation).entrySet()) {
- values.put(entry.getKey().getSimpleName().toString(), entry.getValue().getValue());
- }
- TagAttribute attribute = new TagAttribute();
+ for (ExecutableElement method : ElementFilter.methodsIn(processingEnv.getElementUtils().getAllMembers(type))) {
+ AnnotationMirror annotation = getAnnotation(method, TAG_ATTRIBUTE);
+ if (method.getModifiers().contains(Modifier.PUBLIC) && annotation != null) {
+ String name = String.valueOf(Character.toLowerCase(method.getSimpleName()
+ .charAt(3)))
+ + method.getSimpleName().subSequence(4, method.getSimpleName().length());
+ if (!tag.getSkipAttributes().contains(name)) {
+ Map<String, Object> values = new HashMap<>();
+ for (Entry<? extends ExecutableElement, ? extends AnnotationValue> entry : processingEnv.getElementUtils().getElementValuesWithDefaults(annotation).entrySet()) {
+ values.put(entry.getKey().getSimpleName().toString(), entry.getValue().getValue());
+ }
+ TagAttribute attribute = new TagAttribute();
populateTagAttributes(attribute, values);
attribute.setName(name);
tag.addTagAttribute(attribute);
- }
- }
- }
+ }
+ }
+ }
}
private AnnotationMirror getAnnotation(javax.lang.model.element.Element element, String annotationName) {
- TypeElement annotation = processingEnv.getElementUtils().getTypeElement(annotationName);
- if (element != null && element.getAnnotationMirrors() != null) {
- for (AnnotationMirror mirror : element.getAnnotationMirrors()) {
- if (mirror.getAnnotationType().asElement().equals(annotation)) {
- return mirror;
- }
- }
- }
+ TypeElement annotation = processingEnv.getElementUtils().getTypeElement(annotationName);
+ if (element != null && element.getAnnotationMirrors() != null) {
+ for (AnnotationMirror mirror : element.getAnnotationMirrors()) {
+ if (mirror.getAnnotationType().asElement().equals(annotation)) {
+ return mirror;
+ }
+ }
+ }
return null;
}
@@ -250,9 +230,13 @@
try {
// load template
- Template template = config.getTemplate("tag.ftl");
- String rootDir = (new File(getOption("outTemplatesDir")))
- .getAbsolutePath();
+ Template tagDescription = config.getTemplate("tag-description.ftl");
+ Template tagAttributes = config.getTemplate("tag-attributes.ftl");
+ String outTemplatesDir = getOption("outTemplatesDir");
+ if (outTemplatesDir == null) {
+ throw new IllegalArgumentException("outTemplatesDir was not defined!");
+ }
+ String rootDir = (new File(outTemplatesDir)).getAbsolutePath();
for (Tag tag : tags.values()) {
if (tag.isInclude()) {
// model
@@ -260,8 +244,12 @@
root.put("tag", tag);
try (BufferedWriter writer = new BufferedWriter(new FileWriter(
- new File(rootDir, tag.getName() + ".html")))){
- template.process(root, writer);
+ new File(rootDir, tag.getName() + "-description.html")))) {
+ tagDescription.process(root, writer);
+ }
+ try (BufferedWriter writer = new BufferedWriter(new FileWriter(
+ new File(rootDir, tag.getName() + "-attributes.html")))) {
+ tagAttributes.process(root, writer);
}
}
}
@@ -318,11 +306,15 @@
transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
//create output directory if it does not exists
- File outputFile = new File(getOption("outFile"));
+ String outFile = getOption("outFile");
+ if (outFile == null) {
+ throw new IllegalArgumentException("outFile was not defined!");
+ }
+ File outputFile = new File(outFile);
File parentDir = outputFile.getParentFile();
- if (!parentDir.exists())
+ if (!parentDir.exists()) {
parentDir.mkdirs();
-
+ }
Source source = new DOMSource(document);
Result result = new StreamResult(new OutputStreamWriter(
new FileOutputStream(outputFile)));
@@ -337,7 +329,7 @@
// there is a bug in the 1.5 apt implementation:
// http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6258929
// this is a hack-around
- if (processingEnv.getOptions().containsKey(name)){
+ if (processingEnv.getOptions().containsKey(name)) {
return processingEnv.getOptions().get(name);
}
for (Map.Entry<String, String> entry : processingEnv.getOptions()
@@ -383,7 +375,7 @@
}
private static void appendTextNode(Document doc, Element element, String name,
- String text, boolean cdata) {
+ String text, boolean cdata) {
Text textNode = cdata ? doc.createCDATASection(text) : doc
.createTextNode(text);
Element newElement = doc.createElement(name);
@@ -394,9 +386,8 @@
/**
* Get values of annotation
*
- * @param declaration The annotation declaration
- * @param type
- * The type of the annotation
+ * @param element The annotation declaration
+ * @param type The type of the annotation
* @return name->value map of annotation values
*/
private Map<String, Object> getValues(javax.lang.model.element.Element element, TypeElement type) {
diff --git a/src/main/resources/org/apache/struts/annotations/taglib/apt/tag-attributes.ftl b/src/main/resources/org/apache/struts/annotations/taglib/apt/tag-attributes.ftl
new file mode 100644
index 0000000..6381753
--- /dev/null
+++ b/src/main/resources/org/apache/struts/annotations/taglib/apt/tag-attributes.ftl
@@ -0,0 +1,26 @@
+<table width="100%">
+ <tr>
+ <td colspan="6"><h4>Dynamic Attributes Allowed:</h4> ${tag.allowDynamicAttributes?string}</td>
+ </tr>
+ <tr>
+ <td colspan="6"> </td>
+ </tr>
+ <tr>
+ <th align="left" valign="top"><h4>Name</h4></th>
+ <th align="left" valign="top"><h4>Required</h4></th>
+ <th align="left" valign="top"><h4>Default</h4></th>
+ <th align="left" valign="top"><h4>Evaluated</h4></th>
+ <th align="left" valign="top"><h4>Type</h4></th>
+ <th align="left" valign="top"><h4>Description</h4></th>
+ </tr>
+ <#list tag.attributes as att>
+ <tr>
+ <td align="left" valign="top">${att.name}</td>
+ <td align="left" valign="top"><#if att.required><strong>true</strong><#else>false</#if></td>
+ <td align="left" valign="top">${att.defaultValue}</td>
+ <td align="left" valign="top">${att.rtexprvalue?string}</td>
+ <td align="left" valign="top">${att.type}</td>
+ <td align="left" valign="top">${att.description}</td>
+ </tr>
+ </#list>
+</table>
diff --git a/src/main/resources/org/apache/struts/annotations/taglib/apt/tag-description.ftl b/src/main/resources/org/apache/struts/annotations/taglib/apt/tag-description.ftl
new file mode 100644
index 0000000..ada8b69
--- /dev/null
+++ b/src/main/resources/org/apache/struts/annotations/taglib/apt/tag-description.ftl
@@ -0,0 +1 @@
+${tag.description}
diff --git a/src/main/resources/org/apache/struts/annotations/taglib/apt/tag.ftl b/src/main/resources/org/apache/struts/annotations/taglib/apt/tag.ftl
deleted file mode 100644
index d7516fe..0000000
--- a/src/main/resources/org/apache/struts/annotations/taglib/apt/tag.ftl
+++ /dev/null
@@ -1,50 +0,0 @@
-<!--
-This file is generated during the build by processing Component class annotations.
-Please do not edit it directly.
--->
-<html>
- <head>
- <title>${tag.name}</title>
- </head>
-
- <body>
- <h1>Tag Name: ${tag.name}</h1>
- <h2>Description</h2>
- <p>
- <!-- START SNIPPET: tagdescription -->
- ${tag.description}
- <!-- END SNIPPET: tagdescription -->
- </p>
-
- <h2>Attributes</h2>
- <!-- START SNIPPET: tagattributes -->
- <table width="100%">
- <tr>
- <td colspan="6"><h4>Dynamic Attributes Allowed:</h4> ${tag.allowDynamicAttributes?string}</td>
- </tr>
- <tr>
- <td colspan="6"> </td>
- </tr>
- <tr>
- <th align="left" valign="top"><h4>Name</h4></th>
- <th align="left" valign="top"><h4>Required</h4></th>
- <th align="left" valign="top"><h4>Default</h4></th>
- <th align="left" valign="top"><h4>Evaluated</h4></th>
- <th align="left" valign="top"><h4>Type</h4></th>
- <th align="left" valign="top"><h4>Description</h4></th>
- </tr>
- <#list tag.attributes as att>
- <tr>
- <td align="left" valign="top">${att.name}</td>
- <td align="left" valign="top"><#if att.required><strong>true</strong><#else>false</#if></td>
- <td align="left" valign="top">${att.defaultValue}</td>
- <td align="left" valign="top">${att.rtexprvalue?string}</td>
- <td align="left" valign="top">${att.type}</td>
- <td align="left" valign="top">${att.description}</td>
- </tr>
- </#list>
- </table>
- <!-- END SNIPPET: tagattributes -->
- </body>
-</html>
-