Here is an implementation of multiline string literals in Java, using Javadoc comments, an annotation and an annotation processor.
This method works by annotating a String
field with a @Multiline
annotation, placing the fields initialisation value in a Javadoc comment, then using an annotation processor to set the fields value to the contents of the Javadoc comment at compile time.
First off, the @Multiline
annotation.
Multiline.java
package org.adrianwalker.multilinestring; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Target(ElementType.FIELD) @Retention(RetentionPolicy.SOURCE) public @interface Multiline { }
Next, the annotation processor to insert the value of the Javadoc comment into the String
field.
MultilineProcessor.java
package org.adrianwalker.multilinestring; import com.sun.tools.javac.model.JavacElements; import com.sun.tools.javac.processing.JavacProcessingEnvironment; import com.sun.tools.javac.tree.JCTree; import com.sun.tools.javac.tree.TreeMaker; import java.util.Set; import javax.annotation.processing.AbstractProcessor; import javax.annotation.processing.ProcessingEnvironment; 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.Element; import javax.lang.model.element.TypeElement; @SupportedAnnotationTypes({"org.adrianwalker.multilinestring.Multiline"}) @SupportedSourceVersion(SourceVersion.RELEASE_6) public final class MultilineProcessor extends AbstractProcessor { private JavacElements elementUtils; private TreeMaker maker; @Override public void init(final ProcessingEnvironment procEnv) { super.init(procEnv); JavacProcessingEnvironment javacProcessingEnv = (JavacProcessingEnvironment) procEnv; this.elementUtils = javacProcessingEnv.getElementUtils(); this.maker = TreeMaker.instance(javacProcessingEnv.getContext()); } @Override public boolean process(final Set<? extends TypeElement> annotations, final RoundEnvironment roundEnv) { Set<? extends Element> fields = roundEnv.getElementsAnnotatedWith(Multiline.class); for (Element field : fields) { String docComment = elementUtils.getDocComment(field); if (null != docComment) { JCTree.JCVariableDecl fieldNode = (JCTree.JCVariableDecl) elementUtils.getTree(field); fieldNode.init = maker.Literal(docComment); } } return true; } }
And finally, a class which demonstrates the usage of the annotation.
MultilineStringUsage.java
package org.adrianwalker.multilinestring; public final class MultilineStringUsage { /** <html><head/><body><p> Hello<br/> Multiline<br/> World<br/></p></body></html> */ @Multiline private static String html; public static void main(final String[] args) { System.out.println(html); } }
Remember to include an <annotationProcessor>
element when compiling classes which use @Multiline
in the compiler plugin configuration when using Maven.
pom.xml
... <plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-compiler-plugin</artifactId><version>2.3.2</version><configuration><source>1.6</source><target>1.6</target><annotationProcessors><annotationProcessor> org.adrianwalker.multilinestring.MultilineProcessor </annotationProcessor></annotationProcessors></configuration></plugin> ...
Source Code
- Multiline String Maven Project - MultilineString.zip
- Multiline String Usage Maven Project - MultilineStringUsage.zip
Usage
Build and install the Multiline String project which contains the @Multiline
annotation and annotation processor, using 'mvn clean install
'.
Build and install the Multiline String Usage project which contains an example of how to use the @Multiline
annotation, using 'mvn clean install
'.
Run the MultilineStringUsage
class to output the multiline string.