Merge branch '2-implement-list-for-config-objects' into 'main'

Resolve "implement List for config objects"

Closes #2

See merge request nairah1/jackfruit!2
This commit is contained in:
Hari Nair
2022-09-22 17:45:33 +00:00
40 changed files with 1763 additions and 701 deletions

73
.gitlab-ci.yml Normal file
View File

@@ -0,0 +1,73 @@
stages:
- build
- verify
- document
- deploy
variables:
JAVA_HOME: "/usr/lib/jvm/java-17-openjdk-amd64" # Sets Java version to run (see /opt for details)
VERSION_COMMIT: "GitLab CI Versioning Commit" # Commit text for version update
VERSION_BRANCH: "update_version" # Branch used to merge version update commit
# Sets the artifact cache to a local directory within build area
MAVEN_CLI_OPTS: "-Dmaven.repo.local=.m2/repository --batch-mode -Dorg.slf4j.simpleLogger.log.org.apache.maven.cli.transfer.Slf4jMavenTransferListener=WARN"
#Workflow rules that filters across the entire pipeline. Cleaner than -o ci.skip since there won't be a "skipped" pipeline.
workflow:
rules:
# If user is not the runner, branch is the default branch, and the pipeline source is a push
- if: '$GITLAB_USER_LOGIN != $RUNNER_USER_LOGIN && $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH && $CI_PIPELINE_SOURCE == "push"'
when: always
# if the first statement fails, never succeed
- when: never
# Cache the artifact repository (not the target directory, as that causes old classes that are deleted to persist, and be deployed when they shouldn't be).
cache:
paths:
- .m2/repository/
maven build:
stage: build
script:
# --- Checks if code compiles
- mvn $MAVEN_CLI_OPTS clean compile
maven verify:
stage: verify
script:
# -fn indicates that it should never fail, this allows artifacts to be built even when unit tests fail to execute successfully
- mvn $MAVEN_CLI_OPTS clean verify
# instruct gitlab to capture the test reports
# test reporting to be handled in gitlab requires:
# sudo gitlab-rails console
# irb(main):001:0> Feature.enable(:junit_pipeline_view,Project.find(84))
artifacts:
reports:
junit:
- target/surefire-reports/TEST-*.xml
- target/failsafe-reports/TEST-*.xml
# Allows a this job to fail, and the pipeline will continue
allow_failure: true
maven document:
stage: document
script:
- mvn $MAVEN_CLI_OPTS clean -DadditionalJOption=-Xdoclint:none javadoc:aggregate-jar
maven deploy:
stage: deploy
script:
# --- set version to date+hash
- UPDATED_VERSION=$(date -u +"%y.%m.%d")-$CI_COMMIT_SHORT_SHA
- echo updated deployment version to $UPDATED_VERSION
# --- Set the update version in the pom file(s)
- mvn $MAVEN_CLI_OPTS versions:set -q -DnewVersion=${UPDATED_VERSION}
# --- Deploy to artifactory
# Again, -fn might be necessary here if artifacts are to be deployed even when unit tests fail
# -DskipTests will not execute unit tests, this should allow the artifact to be deployed if unit tests fail in the previous stage
# -Dmaven.test.skip=true will also stop the unit tests from being compiled--which potentially would speed this up
# -Dmaven.javadoc.failOnError=false instructs this to proceed even if javadoc generation fails
- mvn $MAVEN_CLI_OPTS -DskipTests -Dmaven.javadoc.failOnError=false clean deploy
when: manual

View File

@@ -1,17 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>jackfruit</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.m2e.core.maven2Builder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.m2e.core.maven2Nature</nature>
</natures>
</projectDescription>

View File

@@ -1,2 +0,0 @@
eclipse.preferences.version=1
encoding/<project>=UTF-8

View File

@@ -1,13 +1,24 @@
# jackfruit
## Quick start
Jackfruit processes annotations on Java interfaces to generate code that can read and write Apache Configuration files. The `demo` module includes sample code. In the top level directory, run `mvn clean package`, which will build the annotation library, run the annotation processor on the file `demo/src/main/java/jackfruit/demo/DemoConfig.java`, and generate the class `demo/target/generated-sources/annotations/jackfruit/demo/DemoConfigFactory.java`. The file `demo/src/main/java/jackfruit/demo/JackfruitDemo.java` shows some simple examples of use.
## Introduction
Jackfruit processes annotations on Java interfaces to generate code that can read and write Apache Configuration files. Include Jackfruit in your project with the following POM:
Include Jackfruit in your project with the following POM:
```
POM GOES HERE
<dependency>
<groupId>edu.jhuapl.ses.srn</groupId>
<artifactId>jackfruit</artifactId>
<version>$VERSION</version>
<type>pom</type>
</dependency>
```
Find the latest version at [Surfshop](http://surfshop:8082/ui/repos/tree/General/libs-snapshot-local/edu/jhuapl/ses/srn/jackfruit/).
An example of an annotated interface is
```
@Jackfruit(prefix = "prefix")
@@ -29,17 +40,34 @@ public interface DemoConfig {
@DefaultValue("serialized string")
@ParserClass(SomeRandomClassParser.class)
public SomeRandomClass randomClass();
@Comment("List of Doubles")
@DefaultValue("0. 5.34 17")
List<Double> doubles();
@Comment("List of RandomClass")
@DefaultValue("obj1 obj2")
@ParserClass(SomeRandomClassParser.class)
List<SomeRandomClass> randoms();
}
```
This corresponds to this Apache Configuration file:
```
# field comment
# field comment
prefix.key = 0
prefix.doubleMethod = 0.0
prefix.StringMethod = Default String
# This string is serialized into an object
prefix.randomClass = serialized string
# List of Doubles
prefix.doubles = 0.0
prefix.doubles = 5.34
prefix.doubles = 17.0
# List of RandomClass
prefix.randoms = obj1
prefix.randoms = obj2
```
The annotation processor generates a class called DemoConfigFactory. An example of use is
@@ -51,8 +79,7 @@ The annotation processor generates a class called DemoConfigFactory. An example
DemoConfig template = factory.getTemplate();
// generate an Apache PropertiesConfiguration object. This can be written out to a file
PropertiesConfiguration config =
factory.toConfig(template, new PropertiesConfigurationLayout());
PropertiesConfiguration config = factory.toConfig(template);
try {
// this is the template, with comments

View File

@@ -1,9 +0,0 @@
eclipse.preferences.version=1
org.eclipse.jdt.core.compiler.codegen.targetPlatform=17
org.eclipse.jdt.core.compiler.compliance=17
org.eclipse.jdt.core.compiler.problem.enablePreviewFeatures=disabled
org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning
org.eclipse.jdt.core.compiler.problem.reportPreviewFeatures=ignore
org.eclipse.jdt.core.compiler.processAnnotations=enabled
org.eclipse.jdt.core.compiler.release=enabled
org.eclipse.jdt.core.compiler.source=17

View File

@@ -1,4 +0,0 @@
activeProfiles=
eclipse.preferences.version=1
resolveWorkspaceProjects=true
version=1

View File

@@ -1,18 +0,0 @@
package jackfruit.processor;
import java.util.Optional;
import javax.lang.model.type.TypeMirror;
import org.immutables.value.Value;
@Value.Immutable
public interface AnnotationBundle {
public String comment();
public String defaultValue();
public String key();
public Optional<TypeMirror> parserClass();
}

View File

@@ -1,15 +0,0 @@
package jackfruit.processor;
import org.apache.commons.configuration2.Configuration;
import org.apache.commons.configuration2.PropertiesConfiguration;
import org.apache.commons.configuration2.PropertiesConfigurationLayout;
public interface ConfigFactory<T> {
public T getTemplate();
public T fromConfig(Configuration config);
public PropertiesConfiguration toConfig(T t, PropertiesConfigurationLayout layout);
}

View File

@@ -1,368 +0,0 @@
package jackfruit.processor;
import java.io.IOException;
import java.io.PrintWriter;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.Messager;
import javax.annotation.processing.Processor;
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.ElementKind;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.Modifier;
import javax.lang.model.element.PackageElement;
import javax.lang.model.element.TypeElement;
import javax.lang.model.type.MirroredTypeException;
import javax.lang.model.type.TypeKind;
import javax.lang.model.type.TypeMirror;
import javax.lang.model.util.Elements;
import javax.lang.model.util.Types;
import javax.tools.Diagnostic;
import javax.tools.JavaFileObject;
import com.google.auto.service.AutoService;
import com.squareup.javapoet.ClassName;
import com.squareup.javapoet.FieldSpec;
import com.squareup.javapoet.JavaFile;
import com.squareup.javapoet.MethodSpec;
import com.squareup.javapoet.ParameterSpec;
import com.squareup.javapoet.ParameterizedTypeName;
import com.squareup.javapoet.TypeName;
import com.squareup.javapoet.TypeSpec;
import com.squareup.javapoet.TypeVariableName;
import jackfruit.annotations.Comment;
import jackfruit.annotations.Jackfruit;
import jackfruit.annotations.DefaultValue;
import jackfruit.annotations.Key;
import jackfruit.annotations.ParserClass;
/**
* https://www.javacodegeeks.com/2015/09/java-annotation-processors.html
*
* @author nairah1
*
*/
@SupportedSourceVersion(SourceVersion.RELEASE_17)
@SupportedAnnotationTypes("jackfruit.annotations.Jackfruit")
@AutoService(Processor.class)
public class ConfigProcessor extends AbstractProcessor {
@Override
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
List<Class<? extends Annotation>> supportedMethodAnnotations = new ArrayList<>();
supportedMethodAnnotations.add(Comment.class);
supportedMethodAnnotations.add(DefaultValue.class);
supportedMethodAnnotations.add(Key.class);
supportedMethodAnnotations.add(ParserClass.class);
Messager messager = processingEnv.getMessager();
List<Element> annotatedInterfaces = roundEnv.getElementsAnnotatedWith(Jackfruit.class).stream()
.filter(e -> e.getKind() == ElementKind.INTERFACE).collect(Collectors.toList());
for (Element element : annotatedInterfaces) {
try {
if (element instanceof TypeElement) {
TypeElement annotatedType = (TypeElement) element;
Jackfruit configParams = (Jackfruit) annotatedType.getAnnotation(Jackfruit.class);
String prefix = configParams.prefix();
if (prefix.length() > 0)
prefix += ".";
// This is the templatized class; e.g. "ConfigTemplate"
TypeVariableName tvn = TypeVariableName.get(annotatedType.getSimpleName().toString());
// This is the generic class; e.g. "ConfigFactory<TestConfig>"
ParameterizedTypeName ptn = ParameterizedTypeName
.get(ClassName.get(jackfruit.processor.ConfigFactory.class), tvn);
String factoryName = String.format("%sFactory", annotatedType.getSimpleName());
TypeSpec.Builder classBuilder = TypeSpec.classBuilder(factoryName)
.addModifiers(Modifier.PUBLIC, Modifier.FINAL).addSuperinterface(ptn);
FieldSpec loggerField = FieldSpec.builder(org.apache.logging.log4j.Logger.class, "logger")
.initializer("$T.getLogger()", org.apache.logging.log4j.LogManager.class)
.addModifiers(Modifier.PRIVATE, Modifier.FINAL, Modifier.STATIC).build();
classBuilder.addField(loggerField);
List<ExecutableElement> enclosedMethods = new ArrayList<>();
for (Element e : annotatedType.getEnclosedElements()) {
if (e.getKind() == ElementKind.METHOD && e instanceof ExecutableElement)
enclosedMethods.add((ExecutableElement) e);
}
for (ExecutableElement e : enclosedMethods) {
messager.printMessage(Diagnostic.Kind.NOTE,
String.format("Annotated method %s\n", e.getSimpleName()));
for (var a : supportedMethodAnnotations) {
if (e.getAnnotation(a) != null)
messager.printMessage(Diagnostic.Kind.NOTE,
String.format("annotated with %s\n", a.getName()));
}
}
Map<ExecutableElement, AnnotationBundle> annotationsMap = new LinkedHashMap<>();
for (ExecutableElement e : enclosedMethods) {
ImmutableAnnotationBundle.Builder builder = ImmutableAnnotationBundle.builder();
builder.key(e.getSimpleName().toString());
builder.comment("");
String defaultValue = null;
List<Annotation> methodAnnotations = new ArrayList<>();
for (var a : supportedMethodAnnotations)
methodAnnotations.add(e.getAnnotation(a));
for (Annotation annotation : methodAnnotations) {
if (annotation == null)
continue;
if (annotation instanceof Key) {
builder.key(((Key) annotation).value());
} else if (annotation instanceof Comment) {
builder.comment(((Comment) annotation).value());
} else if (annotation instanceof DefaultValue) {
DefaultValue d = (DefaultValue) annotation;
defaultValue = d.value();
} else if (annotation instanceof ParserClass) {
ParserClass pc = (ParserClass) annotation;
TypeMirror tm;
try {
// see
// https://stackoverflow.com/questions/7687829/java-6-annotation-processing-getting-a-class-from-an-annotation
tm = processingEnv.getElementUtils().getTypeElement(pc.value().toString())
.asType();
} catch (MirroredTypeException mte) {
tm = mte.getTypeMirror();
}
builder.parserClass(tm);
} else {
throw new IllegalArgumentException(
"Unknown annotation type " + annotation.getClass().getSimpleName());
}
}
if (defaultValue == null) {
messager.printMessage(Diagnostic.Kind.ERROR,
String.format("No default value on method %s!", e.getSimpleName()));
continue;
}
builder.defaultValue(defaultValue);
annotationsMap.put(e, builder.build());
}
List<MethodSpec> methods = new ArrayList<>();
for (Method m : ConfigFactory.class.getMethods()) {
if (m.getName().equals("toConfig")) {
MethodSpec toConfig = buildToConfig(tvn, m, annotationsMap, prefix);
methods.add(toConfig);
}
if (m.getName().equals("getTemplate")) {
MethodSpec getTemplate = buildGetTemplate(tvn, m, annotationsMap, prefix);
methods.add(getTemplate);
}
if (m.getName().equals("fromConfig")) {
MethodSpec fromConfig = buildFromConfig(tvn, m, annotationsMap, prefix);
methods.add(fromConfig);
}
}
classBuilder.addMethods(methods);
TypeSpec thisClass = classBuilder.build();
PackageElement pkg = processingEnv.getElementUtils().getPackageOf(annotatedType);
JavaFileObject jfo =
processingEnv.getFiler().createSourceFile(pkg.getQualifiedName() + "." + factoryName);
JavaFile javaFile = JavaFile.builder(pkg.toString(), thisClass).build();
try (PrintWriter pw = new PrintWriter(jfo.openWriter())) {
javaFile.writeTo(pw);
}
messager.printMessage(Diagnostic.Kind.NOTE,
String.format("wrote %s", javaFile.toJavaFileObject().toUri()));
}
} catch (IOException e1) {
messager.printMessage(Diagnostic.Kind.ERROR, e1.getLocalizedMessage());
e1.printStackTrace();
}
}
return true;
}
private MethodSpec buildToConfig(TypeVariableName tvn, Method m,
Map<ExecutableElement, AnnotationBundle> annotationsMap, String prefix) {
ParameterSpec ps = ParameterSpec.builder(tvn, "t").build();
ParameterSpec layout = ParameterSpec.builder(TypeVariableName.get(
org.apache.commons.configuration2.PropertiesConfigurationLayout.class.getCanonicalName()),
"layout").build();
MethodSpec.Builder methodBuilder =
MethodSpec.methodBuilder(m.getName()).addAnnotation(Override.class)
.addModifiers(Modifier.PUBLIC).returns(m.getGenericReturnType());
methodBuilder.addParameter(ps);
methodBuilder.addParameter(layout);
methodBuilder.addStatement("$T config = new $T()",
org.apache.commons.configuration2.PropertiesConfiguration.class,
org.apache.commons.configuration2.PropertiesConfiguration.class);
methodBuilder.addStatement("config.setLayout($N)", layout);
boolean needBlank = true;
for (ExecutableElement method : annotationsMap.keySet()) {
AnnotationBundle ab = annotationsMap.get(method);
String key = prefix + ab.key();
if (needBlank) {
methodBuilder.addStatement(String.format("$N.setBlancLinesBefore(\"%s\", 1)", key), layout);
needBlank = false;
}
if (ab.parserClass().isPresent()) {
TypeMirror parser = ab.parserClass().get();
String parserName = method.getSimpleName() + "parser";
methodBuilder.addStatement("$T " + parserName + " = new $T()", parser, parser);
methodBuilder.addStatement(String.format("config.setProperty(\"%s\", %s.toString($N.%s()))",
key, parserName, method.getSimpleName()), ps);
} else {
methodBuilder.addStatement(
String.format("config.setProperty(\"%s\", t.%s())", key, method.getSimpleName()));
}
if (ab.comment().length() > 0)
methodBuilder.addStatement(
String.format("$N.setComment(\"%s\", \"%s\")", key, ab.comment()), layout);
}
methodBuilder.addCode("return config;");
return methodBuilder.build();
}
private MethodSpec buildGetTemplate(TypeVariableName tvn, Method m,
Map<ExecutableElement, AnnotationBundle> annotationsMap, String prefix) {
MethodSpec.Builder methodBuilder = MethodSpec.methodBuilder(m.getName())
.addAnnotation(Override.class).addModifiers(Modifier.PUBLIC).returns(tvn);
TypeSpec.Builder typeBuilder = TypeSpec.anonymousClassBuilder("").addSuperinterface(tvn);
for (ExecutableElement method : annotationsMap.keySet()) {
AnnotationBundle bundle = annotationsMap.get(method);
MethodSpec.Builder builder =
MethodSpec.methodBuilder(method.getSimpleName().toString()).addModifiers(Modifier.PUBLIC)
.returns(TypeName.get(method.getReturnType())).addJavadoc(bundle.comment());
if (bundle.parserClass().isPresent()) {
// it's a custom class
TypeMirror parser = bundle.parserClass().get();
builder.addStatement("$T parser = new $T()", parser, parser);
builder
.addStatement(String.format("return parser.fromString(\"%s\")", bundle.defaultValue()));
} else {
// it's a built in type
Elements elements = processingEnv.getElementUtils();
Types types = processingEnv.getTypeUtils();
TypeMirror returnType = method.getReturnType();
if (types.isAssignable(returnType, elements.getTypeElement("java.lang.String").asType())) {
// it's a string
builder.addStatement(String.format("return \"%s\"", bundle.defaultValue()));
} else {
TypeKind kind = method.getReturnType().getKind();
if (kind.isPrimitive()) {
builder.addStatement(String.format("return %s", bundle.defaultValue()));
} else {
// assume it's boxed?
builder.addStatement(String.format("return %s", bundle.defaultValue()));
}
}
}
typeBuilder.addMethod(builder.build());
}
methodBuilder.addStatement("return $L", typeBuilder.build());
return methodBuilder.build();
}
private MethodSpec buildFromConfig(TypeVariableName tvn, Method m,
Map<ExecutableElement, AnnotationBundle> annotationsMap, String prefix) {
MethodSpec.Builder methodBuilder = MethodSpec.methodBuilder(m.getName())
.addAnnotation(Override.class).addModifiers(Modifier.PUBLIC).returns(tvn)
.addParameter(org.apache.commons.configuration2.Configuration.class, "config");
TypeSpec.Builder typeBuilder = TypeSpec.anonymousClassBuilder("").addSuperinterface(tvn);
for (ExecutableElement method : annotationsMap.keySet()) {
AnnotationBundle bundle = annotationsMap.get(method);
MethodSpec.Builder builder =
MethodSpec.methodBuilder(method.getSimpleName().toString()).addModifiers(Modifier.PUBLIC)
.returns(TypeName.get(method.getReturnType())).addJavadoc(bundle.comment());
if (bundle.parserClass().isPresent()) {
TypeMirror parser = bundle.parserClass().get();
builder.addStatement("$T parser = new $T()", parser, parser);
builder.addStatement(String.format("return parser.fromString(config.getString(\"%s\"))",
prefix + bundle.key()));
} else {
Elements elements = processingEnv.getElementUtils();
Types types = processingEnv.getTypeUtils();
TypeMirror returnType = method.getReturnType();
if (types.isAssignable(returnType, elements.getTypeElement("java.lang.Boolean").asType())) {
builder.addStatement(
String.format("return config.getBoolean(\"%s\")", prefix + bundle.key()));
} else if (types.isAssignable(returnType,
elements.getTypeElement("java.lang.Byte").asType())) {
builder
.addStatement(String.format("return config.getByte(\"%s\")", prefix + bundle.key()));
} else if (types.isAssignable(returnType,
elements.getTypeElement("java.lang.Double").asType())) {
builder.addStatement(
String.format("return config.getDouble(\"%s\")", prefix + bundle.key()));
} else if (types.isAssignable(returnType,
elements.getTypeElement("java.lang.Float").asType())) {
builder
.addStatement(String.format("return config.getFloat(\"%s\")", prefix + bundle.key()));
} else if (types.isAssignable(returnType,
elements.getTypeElement("java.lang.Integer").asType())) {
builder
.addStatement(String.format("return config.getInt(\"%s\")", prefix + bundle.key()));
} else if (types.isAssignable(returnType,
elements.getTypeElement("java.lang.Long").asType())) {
builder
.addStatement(String.format("return config.getLong(\"%s\")", prefix + bundle.key()));
} else if (types.isAssignable(returnType,
elements.getTypeElement("java.lang.Short").asType())) {
builder
.addStatement(String.format("return config.getShort(\"%s\")", prefix + bundle.key()));
} else if (types.isAssignable(returnType,
elements.getTypeElement("java.lang.String").asType())) {
builder.addStatement(
String.format("return config.getString(\"%s\")", prefix + bundle.key()));
} else {
processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR,
"Can't handle return type " + m.getReturnType().getCanonicalName());
}
}
typeBuilder.addMethod(builder.build());
}
methodBuilder.addStatement("return $L", typeBuilder.build());
return methodBuilder.build();
}
}

View File

@@ -13,17 +13,8 @@
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="src" path="target/generated-sources/annotations">
<attributes>
<attribute name="ignore_optional_problems" value="true"/>
<attribute name="optional" value="true"/>
<attribute name="maven.pomderived" value="true"/>
<attribute name="m2e-apt" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-17">
<attributes>
<attribute name="module" value="true"/>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
@@ -32,13 +23,15 @@
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="src" path="target/generated-sources/annotations">
<attributes>
<attribute name="optional" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="src" output="target/test-classes" path="target/generated-test-sources/test-annotations">
<attributes>
<attribute name="ignore_optional_problems" value="true"/>
<attribute name="test" value="true"/>
<attribute name="optional" value="true"/>
<attribute name="maven.pomderived" value="true"/>
<attribute name="m2e-apt" value="true"/>
<attribute name="test" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="output" path="target/classes"/>

View File

@@ -7,3 +7,398 @@ org.eclipse.jdt.core.compiler.problem.reportPreviewFeatures=ignore
org.eclipse.jdt.core.compiler.processAnnotations=enabled
org.eclipse.jdt.core.compiler.release=disabled
org.eclipse.jdt.core.compiler.source=17
org.eclipse.jdt.core.formatter.align_assignment_statements_on_columns=false
org.eclipse.jdt.core.formatter.align_fields_grouping_blank_lines=2147483647
org.eclipse.jdt.core.formatter.align_selector_in_method_invocation_on_expression_first_line=false
org.eclipse.jdt.core.formatter.align_type_members_on_columns=false
org.eclipse.jdt.core.formatter.align_variable_declarations_on_columns=false
org.eclipse.jdt.core.formatter.align_with_spaces=false
org.eclipse.jdt.core.formatter.alignment_for_additive_operator=16
org.eclipse.jdt.core.formatter.alignment_for_annotations_on_enum_constant=0
org.eclipse.jdt.core.formatter.alignment_for_annotations_on_field=49
org.eclipse.jdt.core.formatter.alignment_for_annotations_on_local_variable=49
org.eclipse.jdt.core.formatter.alignment_for_annotations_on_method=49
org.eclipse.jdt.core.formatter.alignment_for_annotations_on_package=49
org.eclipse.jdt.core.formatter.alignment_for_annotations_on_parameter=0
org.eclipse.jdt.core.formatter.alignment_for_annotations_on_type=49
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression=16
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_annotation=16
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant=16
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_call=16
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation=16
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression=16
org.eclipse.jdt.core.formatter.alignment_for_assertion_message=0
org.eclipse.jdt.core.formatter.alignment_for_assignment=16
org.eclipse.jdt.core.formatter.alignment_for_bitwise_operator=16
org.eclipse.jdt.core.formatter.alignment_for_compact_if=16
org.eclipse.jdt.core.formatter.alignment_for_compact_loops=16
org.eclipse.jdt.core.formatter.alignment_for_conditional_expression=80
org.eclipse.jdt.core.formatter.alignment_for_conditional_expression_chain=0
org.eclipse.jdt.core.formatter.alignment_for_enum_constants=0
org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer=16
org.eclipse.jdt.core.formatter.alignment_for_expressions_in_for_loop_header=0
org.eclipse.jdt.core.formatter.alignment_for_expressions_in_switch_case_with_arrow=0
org.eclipse.jdt.core.formatter.alignment_for_expressions_in_switch_case_with_colon=0
org.eclipse.jdt.core.formatter.alignment_for_logical_operator=16
org.eclipse.jdt.core.formatter.alignment_for_method_declaration=0
org.eclipse.jdt.core.formatter.alignment_for_module_statements=16
org.eclipse.jdt.core.formatter.alignment_for_multiple_fields=16
org.eclipse.jdt.core.formatter.alignment_for_multiplicative_operator=16
org.eclipse.jdt.core.formatter.alignment_for_parameterized_type_references=0
org.eclipse.jdt.core.formatter.alignment_for_parameters_in_constructor_declaration=16
org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration=16
org.eclipse.jdt.core.formatter.alignment_for_record_components=16
org.eclipse.jdt.core.formatter.alignment_for_relational_operator=0
org.eclipse.jdt.core.formatter.alignment_for_resources_in_try=80
org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation=16
org.eclipse.jdt.core.formatter.alignment_for_shift_operator=0
org.eclipse.jdt.core.formatter.alignment_for_string_concatenation=16
org.eclipse.jdt.core.formatter.alignment_for_superclass_in_type_declaration=16
org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_enum_declaration=16
org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_record_declaration=16
org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration=16
org.eclipse.jdt.core.formatter.alignment_for_switch_case_with_arrow=0
org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_constructor_declaration=16
org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_method_declaration=16
org.eclipse.jdt.core.formatter.alignment_for_type_annotations=0
org.eclipse.jdt.core.formatter.alignment_for_type_arguments=0
org.eclipse.jdt.core.formatter.alignment_for_type_parameters=0
org.eclipse.jdt.core.formatter.alignment_for_union_type_in_multicatch=16
org.eclipse.jdt.core.formatter.blank_lines_after_imports=1
org.eclipse.jdt.core.formatter.blank_lines_after_last_class_body_declaration=0
org.eclipse.jdt.core.formatter.blank_lines_after_package=1
org.eclipse.jdt.core.formatter.blank_lines_before_abstract_method=1
org.eclipse.jdt.core.formatter.blank_lines_before_field=0
org.eclipse.jdt.core.formatter.blank_lines_before_first_class_body_declaration=0
org.eclipse.jdt.core.formatter.blank_lines_before_imports=0
org.eclipse.jdt.core.formatter.blank_lines_before_member_type=0
org.eclipse.jdt.core.formatter.blank_lines_before_method=1
org.eclipse.jdt.core.formatter.blank_lines_before_new_chunk=1
org.eclipse.jdt.core.formatter.blank_lines_before_package=0
org.eclipse.jdt.core.formatter.blank_lines_between_import_groups=0
org.eclipse.jdt.core.formatter.blank_lines_between_statement_group_in_switch=0
org.eclipse.jdt.core.formatter.blank_lines_between_type_declarations=2
org.eclipse.jdt.core.formatter.brace_position_for_annotation_type_declaration=end_of_line
org.eclipse.jdt.core.formatter.brace_position_for_anonymous_type_declaration=end_of_line
org.eclipse.jdt.core.formatter.brace_position_for_array_initializer=end_of_line
org.eclipse.jdt.core.formatter.brace_position_for_block=end_of_line
org.eclipse.jdt.core.formatter.brace_position_for_block_in_case=end_of_line
org.eclipse.jdt.core.formatter.brace_position_for_constructor_declaration=end_of_line
org.eclipse.jdt.core.formatter.brace_position_for_enum_constant=end_of_line
org.eclipse.jdt.core.formatter.brace_position_for_enum_declaration=end_of_line
org.eclipse.jdt.core.formatter.brace_position_for_lambda_body=end_of_line
org.eclipse.jdt.core.formatter.brace_position_for_method_declaration=end_of_line
org.eclipse.jdt.core.formatter.brace_position_for_record_constructor=end_of_line
org.eclipse.jdt.core.formatter.brace_position_for_record_declaration=end_of_line
org.eclipse.jdt.core.formatter.brace_position_for_switch=end_of_line
org.eclipse.jdt.core.formatter.brace_position_for_type_declaration=end_of_line
org.eclipse.jdt.core.formatter.comment.align_tags_descriptions_grouped=false
org.eclipse.jdt.core.formatter.comment.align_tags_names_descriptions=false
org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_block_comment=false
org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_javadoc_comment=false
org.eclipse.jdt.core.formatter.comment.count_line_length_from_starting_position=true
org.eclipse.jdt.core.formatter.comment.format_block_comments=true
org.eclipse.jdt.core.formatter.comment.format_header=true
org.eclipse.jdt.core.formatter.comment.format_html=true
org.eclipse.jdt.core.formatter.comment.format_javadoc_comments=true
org.eclipse.jdt.core.formatter.comment.format_line_comments=true
org.eclipse.jdt.core.formatter.comment.format_source_code=true
org.eclipse.jdt.core.formatter.comment.indent_parameter_description=false
org.eclipse.jdt.core.formatter.comment.indent_root_tags=true
org.eclipse.jdt.core.formatter.comment.indent_tag_description=false
org.eclipse.jdt.core.formatter.comment.insert_new_line_before_root_tags=insert
org.eclipse.jdt.core.formatter.comment.insert_new_line_between_different_tags=do not insert
org.eclipse.jdt.core.formatter.comment.insert_new_line_for_parameter=do not insert
org.eclipse.jdt.core.formatter.comment.line_length=100
org.eclipse.jdt.core.formatter.comment.new_lines_at_block_boundaries=true
org.eclipse.jdt.core.formatter.comment.new_lines_at_javadoc_boundaries=true
org.eclipse.jdt.core.formatter.comment.preserve_white_space_between_code_and_line_comments=false
org.eclipse.jdt.core.formatter.compact_else_if=true
org.eclipse.jdt.core.formatter.continuation_indentation=2
org.eclipse.jdt.core.formatter.continuation_indentation_for_array_initializer=2
org.eclipse.jdt.core.formatter.disabling_tag=@formatter\:off
org.eclipse.jdt.core.formatter.enabling_tag=@formatter\:on
org.eclipse.jdt.core.formatter.format_guardian_clause_on_one_line=false
org.eclipse.jdt.core.formatter.format_line_comment_starting_on_first_column=true
org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_annotation_declaration_header=true
org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_constant_header=true
org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_declaration_header=true
org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_record_header=true
org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_type_header=true
org.eclipse.jdt.core.formatter.indent_breaks_compare_to_cases=true
org.eclipse.jdt.core.formatter.indent_empty_lines=false
org.eclipse.jdt.core.formatter.indent_statements_compare_to_block=true
org.eclipse.jdt.core.formatter.indent_statements_compare_to_body=true
org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_cases=true
org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_switch=true
org.eclipse.jdt.core.formatter.indentation.size=4
org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_enum_constant=insert
org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_field=insert
org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_local_variable=insert
org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_method=insert
org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_package=insert
org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_parameter=do not insert
org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_type=insert
org.eclipse.jdt.core.formatter.insert_new_line_after_label=do not insert
org.eclipse.jdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer=do not insert
org.eclipse.jdt.core.formatter.insert_new_line_after_type_annotation=do not insert
org.eclipse.jdt.core.formatter.insert_new_line_at_end_of_file_if_missing=insert
org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement=do not insert
org.eclipse.jdt.core.formatter.insert_new_line_before_closing_brace_in_array_initializer=do not insert
org.eclipse.jdt.core.formatter.insert_new_line_before_else_in_if_statement=do not insert
org.eclipse.jdt.core.formatter.insert_new_line_before_finally_in_try_statement=do not insert
org.eclipse.jdt.core.formatter.insert_new_line_before_while_in_do_statement=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_additive_operator=insert
org.eclipse.jdt.core.formatter.insert_space_after_and_in_type_parameter=insert
org.eclipse.jdt.core.formatter.insert_space_after_arrow_in_switch_case=insert
org.eclipse.jdt.core.formatter.insert_space_after_arrow_in_switch_default=insert
org.eclipse.jdt.core.formatter.insert_space_after_assignment_operator=insert
org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation_type_declaration=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_bitwise_operator=insert
org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_parameters=insert
org.eclipse.jdt.core.formatter.insert_space_after_closing_brace_in_block=insert
org.eclipse.jdt.core.formatter.insert_space_after_closing_paren_in_cast=insert
org.eclipse.jdt.core.formatter.insert_space_after_colon_in_assert=insert
org.eclipse.jdt.core.formatter.insert_space_after_colon_in_case=insert
org.eclipse.jdt.core.formatter.insert_space_after_colon_in_conditional=insert
org.eclipse.jdt.core.formatter.insert_space_after_colon_in_for=insert
org.eclipse.jdt.core.formatter.insert_space_after_colon_in_labeled_statement=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_allocation_expression=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_annotation=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_array_initializer=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_parameters=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_throws=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_constant_arguments=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_declarations=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_explicitconstructorcall_arguments=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_increments=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_inits=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_parameters=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_throws=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_invocation_arguments=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_field_declarations=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_local_declarations=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_parameterized_type_reference=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_permitted_types=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_record_components=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_superinterfaces=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_switch_case_expressions=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_arguments=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_parameters=insert
org.eclipse.jdt.core.formatter.insert_space_after_ellipsis=insert
org.eclipse.jdt.core.formatter.insert_space_after_lambda_arrow=insert
org.eclipse.jdt.core.formatter.insert_space_after_logical_operator=insert
org.eclipse.jdt.core.formatter.insert_space_after_multiplicative_operator=insert
org.eclipse.jdt.core.formatter.insert_space_after_not_operator=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_parameterized_type_reference=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_arguments=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_parameters=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_brace_in_array_initializer=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_allocation_expression=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_reference=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_annotation=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_cast=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_catch=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_constructor_declaration=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_enum_constant=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_for=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_if=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_declaration=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_invocation=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_parenthesized_expression=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_record_declaration=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_switch=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_synchronized=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_try=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_while=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_postfix_operator=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_prefix_operator=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_question_in_conditional=insert
org.eclipse.jdt.core.formatter.insert_space_after_question_in_wildcard=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_relational_operator=insert
org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_for=insert
org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_try_resources=insert
org.eclipse.jdt.core.formatter.insert_space_after_shift_operator=insert
org.eclipse.jdt.core.formatter.insert_space_after_string_concatenation=insert
org.eclipse.jdt.core.formatter.insert_space_after_unary_operator=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_additive_operator=insert
org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter=insert
org.eclipse.jdt.core.formatter.insert_space_before_arrow_in_switch_case=insert
org.eclipse.jdt.core.formatter.insert_space_before_arrow_in_switch_default=insert
org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator=insert
org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration=insert
org.eclipse.jdt.core.formatter.insert_space_before_bitwise_operator=insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_parameterized_type_reference=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_arguments=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_parameters=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_brace_in_array_initializer=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_allocation_expression=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_reference=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_annotation=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_cast=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_catch=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_constructor_declaration=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_enum_constant=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_for=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_if=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_declaration=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_invocation=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_parenthesized_expression=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_record_declaration=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_switch=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_synchronized=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_try=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_while=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_colon_in_assert=insert
org.eclipse.jdt.core.formatter.insert_space_before_colon_in_case=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_colon_in_conditional=insert
org.eclipse.jdt.core.formatter.insert_space_before_colon_in_default=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_colon_in_for=insert
org.eclipse.jdt.core.formatter.insert_space_before_colon_in_labeled_statement=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_allocation_expression=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_annotation=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_array_initializer=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_parameters=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_throws=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_constant_arguments=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_declarations=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_explicitconstructorcall_arguments=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_increments=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_inits=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_parameters=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_throws=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_field_declarations=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_local_declarations=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_parameterized_type_reference=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_permitted_types=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_record_components=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_superinterfaces=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_switch_case_expressions=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_arguments=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_ellipsis=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_lambda_arrow=insert
org.eclipse.jdt.core.formatter.insert_space_before_logical_operator=insert
org.eclipse.jdt.core.formatter.insert_space_before_multiplicative_operator=insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_parameterized_type_reference=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_arguments=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_parameters=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_annotation_type_declaration=insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_anonymous_type_declaration=insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_array_initializer=insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_block=insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_constructor_declaration=insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_constant=insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_declaration=insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_method_declaration=insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_record_constructor=insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_record_declaration=insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_switch=insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_type_declaration=insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_allocation_expression=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_reference=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_type_reference=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation_type_member_declaration=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_catch=insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_constructor_declaration=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_enum_constant=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_for=insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_if=insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_declaration=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_invocation=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_parenthesized_expression=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_record_declaration=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_switch=insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_synchronized=insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_try=insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_while=insert
org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_return=insert
org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_throw=insert
org.eclipse.jdt.core.formatter.insert_space_before_postfix_operator=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_prefix_operator=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_question_in_conditional=insert
org.eclipse.jdt.core.formatter.insert_space_before_question_in_wildcard=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_relational_operator=insert
org.eclipse.jdt.core.formatter.insert_space_before_semicolon=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_for=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_try_resources=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_shift_operator=insert
org.eclipse.jdt.core.formatter.insert_space_before_string_concatenation=insert
org.eclipse.jdt.core.formatter.insert_space_before_unary_operator=do not insert
org.eclipse.jdt.core.formatter.insert_space_between_brackets_in_array_type_reference=do not insert
org.eclipse.jdt.core.formatter.insert_space_between_empty_braces_in_array_initializer=do not insert
org.eclipse.jdt.core.formatter.insert_space_between_empty_brackets_in_array_allocation_expression=do not insert
org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_annotation_type_member_declaration=do not insert
org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_constructor_declaration=do not insert
org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_enum_constant=do not insert
org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_declaration=do not insert
org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_invocation=do not insert
org.eclipse.jdt.core.formatter.join_lines_in_comments=true
org.eclipse.jdt.core.formatter.join_wrapped_lines=true
org.eclipse.jdt.core.formatter.keep_annotation_declaration_on_one_line=one_line_never
org.eclipse.jdt.core.formatter.keep_anonymous_type_declaration_on_one_line=one_line_if_empty
org.eclipse.jdt.core.formatter.keep_code_block_on_one_line=one_line_never
org.eclipse.jdt.core.formatter.keep_else_statement_on_same_line=false
org.eclipse.jdt.core.formatter.keep_empty_array_initializer_on_one_line=false
org.eclipse.jdt.core.formatter.keep_enum_constant_declaration_on_one_line=one_line_if_empty
org.eclipse.jdt.core.formatter.keep_enum_declaration_on_one_line=one_line_never
org.eclipse.jdt.core.formatter.keep_if_then_body_block_on_one_line=one_line_never
org.eclipse.jdt.core.formatter.keep_imple_if_on_one_line=false
org.eclipse.jdt.core.formatter.keep_lambda_body_block_on_one_line=one_line_never
org.eclipse.jdt.core.formatter.keep_loop_body_block_on_one_line=one_line_never
org.eclipse.jdt.core.formatter.keep_method_body_on_one_line=one_line_if_empty
org.eclipse.jdt.core.formatter.keep_record_constructor_on_one_line=one_line_if_empty
org.eclipse.jdt.core.formatter.keep_record_declaration_on_one_line=one_line_never
org.eclipse.jdt.core.formatter.keep_simple_do_while_body_on_same_line=false
org.eclipse.jdt.core.formatter.keep_simple_for_body_on_same_line=false
org.eclipse.jdt.core.formatter.keep_simple_getter_setter_on_one_line=false
org.eclipse.jdt.core.formatter.keep_simple_while_body_on_same_line=false
org.eclipse.jdt.core.formatter.keep_switch_body_block_on_one_line=one_line_never
org.eclipse.jdt.core.formatter.keep_switch_case_with_arrow_on_one_line=one_line_never
org.eclipse.jdt.core.formatter.keep_then_statement_on_same_line=false
org.eclipse.jdt.core.formatter.keep_type_declaration_on_one_line=one_line_never
org.eclipse.jdt.core.formatter.lineSplit=100
org.eclipse.jdt.core.formatter.never_indent_block_comments_on_first_column=false
org.eclipse.jdt.core.formatter.never_indent_line_comments_on_first_column=false
org.eclipse.jdt.core.formatter.number_of_blank_lines_after_code_block=0
org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_code_block=0
org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_method_body=0
org.eclipse.jdt.core.formatter.number_of_blank_lines_at_end_of_code_block=0
org.eclipse.jdt.core.formatter.number_of_blank_lines_at_end_of_method_body=0
org.eclipse.jdt.core.formatter.number_of_blank_lines_before_code_block=0
org.eclipse.jdt.core.formatter.number_of_empty_lines_to_preserve=3
org.eclipse.jdt.core.formatter.parentheses_positions_in_annotation=common_lines
org.eclipse.jdt.core.formatter.parentheses_positions_in_catch_clause=common_lines
org.eclipse.jdt.core.formatter.parentheses_positions_in_enum_constant_declaration=common_lines
org.eclipse.jdt.core.formatter.parentheses_positions_in_for_statment=common_lines
org.eclipse.jdt.core.formatter.parentheses_positions_in_if_while_statement=common_lines
org.eclipse.jdt.core.formatter.parentheses_positions_in_lambda_declaration=common_lines
org.eclipse.jdt.core.formatter.parentheses_positions_in_method_delcaration=common_lines
org.eclipse.jdt.core.formatter.parentheses_positions_in_method_invocation=common_lines
org.eclipse.jdt.core.formatter.parentheses_positions_in_record_declaration=common_lines
org.eclipse.jdt.core.formatter.parentheses_positions_in_switch_statement=common_lines
org.eclipse.jdt.core.formatter.parentheses_positions_in_try_clause=common_lines
org.eclipse.jdt.core.formatter.put_empty_statement_on_new_line=false
org.eclipse.jdt.core.formatter.tabulation.char=space
org.eclipse.jdt.core.formatter.tabulation.size=2
org.eclipse.jdt.core.formatter.text_block_indentation=0
org.eclipse.jdt.core.formatter.use_on_off_tags=true
org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations=false
org.eclipse.jdt.core.formatter.wrap_before_additive_operator=true
org.eclipse.jdt.core.formatter.wrap_before_assertion_message_operator=true
org.eclipse.jdt.core.formatter.wrap_before_assignment_operator=false
org.eclipse.jdt.core.formatter.wrap_before_bitwise_operator=true
org.eclipse.jdt.core.formatter.wrap_before_conditional_operator=true
org.eclipse.jdt.core.formatter.wrap_before_logical_operator=true
org.eclipse.jdt.core.formatter.wrap_before_multiplicative_operator=true
org.eclipse.jdt.core.formatter.wrap_before_or_operator_multicatch=true
org.eclipse.jdt.core.formatter.wrap_before_relational_operator=true
org.eclipse.jdt.core.formatter.wrap_before_shift_operator=true
org.eclipse.jdt.core.formatter.wrap_before_string_concatenation=true
org.eclipse.jdt.core.formatter.wrap_before_switch_case_arrow_operator=false
org.eclipse.jdt.core.formatter.wrap_outer_expressions_when_nested=true
org.eclipse.jdt.core.javaFormatter=org.eclipse.jdt.core.defaultJavaFormatter

View File

@@ -0,0 +1,3 @@
eclipse.preferences.version=1
formatter_profile=_GoogleStyle
formatter_settings_version=22

View File

@@ -1,75 +0,0 @@
package jackfruit.demo;
import jackfruit.processor.ConfigFactory;
import java.lang.Double;
import java.lang.Override;
import java.lang.String;
import org.apache.commons.configuration2.Configuration;
import org.apache.commons.configuration2.PropertiesConfiguration;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
public final class DemoConfigFactory implements ConfigFactory<DemoConfig> {
private static final Logger logger = LogManager.getLogger();
@Override
public PropertiesConfiguration toConfig(DemoConfig t) {
PropertiesConfiguration config = new PropertiesConfiguration();
config.setProperty("prefix.key", t.intMethod());
config.setProperty("prefix.doubleMethod", t.doubleMethod());
config.setProperty("prefix.StringMethod", t.StringMethod());
SomeRandomClassParser randomClassparser = new SomeRandomClassParser();
config.setProperty("prefix.randomClass", randomClassparser.toString(t.randomClass()));
return config;
}
@Override
public DemoConfig fromConfig(Configuration config) {
return new DemoConfig() {
/**
* field comment
*/
public int intMethod() {
return config.getInt("prefix.key");
}
public Double doubleMethod() {
return config.getDouble("prefix.doubleMethod");
}
public String StringMethod() {
return config.getString("prefix.StringMethod");
}
public SomeRandomClass randomClass() {
SomeRandomClassParser parser = new SomeRandomClassParser();
return parser.fromString(config.getString("prefix.randomClass"));
}
};
}
@Override
public DemoConfig getTemplate() {
return new DemoConfig() {
/**
* field comment
*/
public int intMethod() {
return 0;
}
public Double doubleMethod() {
return 0.;
}
public String StringMethod() {
return "Default String";
}
public SomeRandomClass randomClass() {
SomeRandomClassParser parser = new SomeRandomClassParser();
return parser.fromString("serialized string");
}
};
}
}

View File

@@ -1,19 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<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/xsd/maven-4.0.0.xsd">
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<artifactId>jackfruit</artifactId>
<artifactId>jackfruit-parent</artifactId>
<groupId>edu.jhuapl.ses.srn</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<artifactId>demo</artifactId>
<artifactId>jackfruit-demo</artifactId>
<name>demo</name>
<!-- FIXME change it to the project's website -->
<url>http://www.example.com</url>
<name>jackfruit-demo</name>
<description>Java Annotations Configuration library demo code</description>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
@@ -35,8 +33,8 @@
</dependency>
<dependency>
<groupId>edu.jhuapl.ses.srn</groupId>
<artifactId>annotations</artifactId>
<version>1.0-SNAPSHOT</version>
<artifactId>jackfruit</artifactId>
<version>${project.parent.version}</version>
</dependency>
<dependency>
<groupId>junit</groupId>
@@ -47,7 +45,7 @@
</dependencies>
<build>
<pluginManagement><!-- lock down plugins versions to avoid using Maven
<pluginManagement> <!-- lock down plugins versions to avoid using Maven
defaults (may be moved to parent pom) -->
<plugins>
<!-- clean lifecycle, see https://maven.apache.org/ref/current/maven-core/lifecycles.html#clean_Lifecycle -->

View File

@@ -1,8 +1,9 @@
package jackfruit.demo;
import java.util.List;
import jackfruit.annotations.Comment;
import jackfruit.annotations.Jackfruit;
import jackfruit.annotations.DefaultValue;
import jackfruit.annotations.Jackfruit;
import jackfruit.annotations.Key;
import jackfruit.annotations.ParserClass;
@@ -52,17 +53,26 @@ public interface DemoConfig {
@Key("key")
@Comment("field comment")
@DefaultValue("0")
public int intMethod();
int intMethod();
@DefaultValue("0.")
public Double doubleMethod();
Double doubleMethod();
@DefaultValue("Default String")
public String StringMethod();
String StringMethod();
@Comment("This string is serialized into an object")
@DefaultValue("serialized string")
@ParserClass(SomeRandomClassParser.class)
public SomeRandomClass randomClass();
SomeRandomClass randomClass();
@Comment("List of Doubles")
@DefaultValue("0. 5.34 17")
List<Double> doubles();
@Comment("List of RandomClass")
@DefaultValue("obj1 obj2")
@ParserClass(SomeRandomClassParser.class)
List<SomeRandomClass> randoms();
}

View File

@@ -3,6 +3,7 @@ package jackfruit.demo;
import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.List;
import org.apache.commons.configuration2.PropertiesConfiguration;
import org.apache.commons.configuration2.PropertiesConfigurationLayout;
import org.apache.commons.configuration2.builder.fluent.Configurations;
@@ -12,26 +13,30 @@ public class JackfruitDemo {
public static void main(String[] args) {
// this factory is built by the annotation processor after reading the DemoConfig interface
// this factory is built by the annotation processor after reading the
// DemoConfig interface
DemoConfigFactory factory = new DemoConfigFactory();
// get an example config object
DemoConfig template = factory.getTemplate();
// generate an Apache PropertiesConfiguration object. This can be written out to a file
// generate an Apache PropertiesConfiguration object. This can be written out to
// a file
PropertiesConfiguration config =
factory.toConfig(template, new PropertiesConfigurationLayout());
try {
// this is the template, with comments
System.out.println("*** This is the template, with default values ***");
config.write(new PrintWriter(System.out));
// write to file
File tmpFile = File.createTempFile("tmp", ".config");
tmpFile.deleteOnExit();
// System.out.println("wrote "+tmpFile.getAbsolutePath());
System.out.println("wrote " + tmpFile.getAbsolutePath());
config.write(new PrintWriter(tmpFile));
System.out.println("\n*** This is the configuration read from " + tmpFile.getAbsolutePath());
// read from file
config = new Configurations().properties(tmpFile);
@@ -46,7 +51,10 @@ public class JackfruitDemo {
template = factory.fromConfig(config);
// get one of the config object's properties
System.out.printf("config.StringMethod() = %s\n", template.StringMethod());
System.out.println("\n*** Retrieving a configuration value");
List<SomeRandomClass> randoms = template.randoms();
for (SomeRandomClass random : randoms)
System.out.println("random.toUpperCase() = " + random.toUpperCase());
}
}

View File

@@ -11,5 +11,9 @@ public class SomeRandomClass {
public SomeRandomClass(String internalString) {
this.internalString = internalString;
}
public String toUpperCase() {
return internalString.toUpperCase();
}
}

View File

@@ -25,17 +25,17 @@ import jackfruit.processor.ConfigProcessor;
*/
public class TestProcessor {
@Test
public void runProcessor() throws Exception {
/*-
System.out.println("TestProcessor");
System.out.println("java.class.path: ");
System.out.println(System.getProperty("java.class.path"));
*/
boolean ignore = true;
if (!ignore) {
Log4j2Configurator lc = Log4j2Configurator.getInstance();

View File

@@ -0,0 +1,404 @@
eclipse.preferences.version=1
org.eclipse.jdt.core.compiler.codegen.targetPlatform=17
org.eclipse.jdt.core.compiler.compliance=17
org.eclipse.jdt.core.compiler.problem.enablePreviewFeatures=disabled
org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning
org.eclipse.jdt.core.compiler.problem.reportPreviewFeatures=ignore
org.eclipse.jdt.core.compiler.processAnnotations=enabled
org.eclipse.jdt.core.compiler.release=enabled
org.eclipse.jdt.core.compiler.source=17
org.eclipse.jdt.core.formatter.align_assignment_statements_on_columns=false
org.eclipse.jdt.core.formatter.align_fields_grouping_blank_lines=2147483647
org.eclipse.jdt.core.formatter.align_selector_in_method_invocation_on_expression_first_line=false
org.eclipse.jdt.core.formatter.align_type_members_on_columns=false
org.eclipse.jdt.core.formatter.align_variable_declarations_on_columns=false
org.eclipse.jdt.core.formatter.align_with_spaces=false
org.eclipse.jdt.core.formatter.alignment_for_additive_operator=16
org.eclipse.jdt.core.formatter.alignment_for_annotations_on_enum_constant=0
org.eclipse.jdt.core.formatter.alignment_for_annotations_on_field=49
org.eclipse.jdt.core.formatter.alignment_for_annotations_on_local_variable=49
org.eclipse.jdt.core.formatter.alignment_for_annotations_on_method=49
org.eclipse.jdt.core.formatter.alignment_for_annotations_on_package=49
org.eclipse.jdt.core.formatter.alignment_for_annotations_on_parameter=0
org.eclipse.jdt.core.formatter.alignment_for_annotations_on_type=49
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression=16
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_annotation=16
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant=16
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_call=16
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation=16
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression=16
org.eclipse.jdt.core.formatter.alignment_for_assertion_message=0
org.eclipse.jdt.core.formatter.alignment_for_assignment=16
org.eclipse.jdt.core.formatter.alignment_for_bitwise_operator=16
org.eclipse.jdt.core.formatter.alignment_for_compact_if=16
org.eclipse.jdt.core.formatter.alignment_for_compact_loops=16
org.eclipse.jdt.core.formatter.alignment_for_conditional_expression=80
org.eclipse.jdt.core.formatter.alignment_for_conditional_expression_chain=0
org.eclipse.jdt.core.formatter.alignment_for_enum_constants=0
org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer=16
org.eclipse.jdt.core.formatter.alignment_for_expressions_in_for_loop_header=0
org.eclipse.jdt.core.formatter.alignment_for_expressions_in_switch_case_with_arrow=0
org.eclipse.jdt.core.formatter.alignment_for_expressions_in_switch_case_with_colon=0
org.eclipse.jdt.core.formatter.alignment_for_logical_operator=16
org.eclipse.jdt.core.formatter.alignment_for_method_declaration=0
org.eclipse.jdt.core.formatter.alignment_for_module_statements=16
org.eclipse.jdt.core.formatter.alignment_for_multiple_fields=16
org.eclipse.jdt.core.formatter.alignment_for_multiplicative_operator=16
org.eclipse.jdt.core.formatter.alignment_for_parameterized_type_references=0
org.eclipse.jdt.core.formatter.alignment_for_parameters_in_constructor_declaration=16
org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration=16
org.eclipse.jdt.core.formatter.alignment_for_record_components=16
org.eclipse.jdt.core.formatter.alignment_for_relational_operator=0
org.eclipse.jdt.core.formatter.alignment_for_resources_in_try=80
org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation=16
org.eclipse.jdt.core.formatter.alignment_for_shift_operator=0
org.eclipse.jdt.core.formatter.alignment_for_string_concatenation=16
org.eclipse.jdt.core.formatter.alignment_for_superclass_in_type_declaration=16
org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_enum_declaration=16
org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_record_declaration=16
org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration=16
org.eclipse.jdt.core.formatter.alignment_for_switch_case_with_arrow=0
org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_constructor_declaration=16
org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_method_declaration=16
org.eclipse.jdt.core.formatter.alignment_for_type_annotations=0
org.eclipse.jdt.core.formatter.alignment_for_type_arguments=0
org.eclipse.jdt.core.formatter.alignment_for_type_parameters=0
org.eclipse.jdt.core.formatter.alignment_for_union_type_in_multicatch=16
org.eclipse.jdt.core.formatter.blank_lines_after_imports=1
org.eclipse.jdt.core.formatter.blank_lines_after_last_class_body_declaration=0
org.eclipse.jdt.core.formatter.blank_lines_after_package=1
org.eclipse.jdt.core.formatter.blank_lines_before_abstract_method=1
org.eclipse.jdt.core.formatter.blank_lines_before_field=0
org.eclipse.jdt.core.formatter.blank_lines_before_first_class_body_declaration=0
org.eclipse.jdt.core.formatter.blank_lines_before_imports=0
org.eclipse.jdt.core.formatter.blank_lines_before_member_type=0
org.eclipse.jdt.core.formatter.blank_lines_before_method=1
org.eclipse.jdt.core.formatter.blank_lines_before_new_chunk=1
org.eclipse.jdt.core.formatter.blank_lines_before_package=0
org.eclipse.jdt.core.formatter.blank_lines_between_import_groups=0
org.eclipse.jdt.core.formatter.blank_lines_between_statement_group_in_switch=0
org.eclipse.jdt.core.formatter.blank_lines_between_type_declarations=2
org.eclipse.jdt.core.formatter.brace_position_for_annotation_type_declaration=end_of_line
org.eclipse.jdt.core.formatter.brace_position_for_anonymous_type_declaration=end_of_line
org.eclipse.jdt.core.formatter.brace_position_for_array_initializer=end_of_line
org.eclipse.jdt.core.formatter.brace_position_for_block=end_of_line
org.eclipse.jdt.core.formatter.brace_position_for_block_in_case=end_of_line
org.eclipse.jdt.core.formatter.brace_position_for_constructor_declaration=end_of_line
org.eclipse.jdt.core.formatter.brace_position_for_enum_constant=end_of_line
org.eclipse.jdt.core.formatter.brace_position_for_enum_declaration=end_of_line
org.eclipse.jdt.core.formatter.brace_position_for_lambda_body=end_of_line
org.eclipse.jdt.core.formatter.brace_position_for_method_declaration=end_of_line
org.eclipse.jdt.core.formatter.brace_position_for_record_constructor=end_of_line
org.eclipse.jdt.core.formatter.brace_position_for_record_declaration=end_of_line
org.eclipse.jdt.core.formatter.brace_position_for_switch=end_of_line
org.eclipse.jdt.core.formatter.brace_position_for_type_declaration=end_of_line
org.eclipse.jdt.core.formatter.comment.align_tags_descriptions_grouped=false
org.eclipse.jdt.core.formatter.comment.align_tags_names_descriptions=false
org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_block_comment=false
org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_javadoc_comment=false
org.eclipse.jdt.core.formatter.comment.count_line_length_from_starting_position=true
org.eclipse.jdt.core.formatter.comment.format_block_comments=true
org.eclipse.jdt.core.formatter.comment.format_header=true
org.eclipse.jdt.core.formatter.comment.format_html=true
org.eclipse.jdt.core.formatter.comment.format_javadoc_comments=true
org.eclipse.jdt.core.formatter.comment.format_line_comments=true
org.eclipse.jdt.core.formatter.comment.format_source_code=true
org.eclipse.jdt.core.formatter.comment.indent_parameter_description=false
org.eclipse.jdt.core.formatter.comment.indent_root_tags=true
org.eclipse.jdt.core.formatter.comment.indent_tag_description=false
org.eclipse.jdt.core.formatter.comment.insert_new_line_before_root_tags=insert
org.eclipse.jdt.core.formatter.comment.insert_new_line_between_different_tags=do not insert
org.eclipse.jdt.core.formatter.comment.insert_new_line_for_parameter=do not insert
org.eclipse.jdt.core.formatter.comment.line_length=100
org.eclipse.jdt.core.formatter.comment.new_lines_at_block_boundaries=true
org.eclipse.jdt.core.formatter.comment.new_lines_at_javadoc_boundaries=true
org.eclipse.jdt.core.formatter.comment.preserve_white_space_between_code_and_line_comments=false
org.eclipse.jdt.core.formatter.compact_else_if=true
org.eclipse.jdt.core.formatter.continuation_indentation=2
org.eclipse.jdt.core.formatter.continuation_indentation_for_array_initializer=2
org.eclipse.jdt.core.formatter.disabling_tag=@formatter\:off
org.eclipse.jdt.core.formatter.enabling_tag=@formatter\:on
org.eclipse.jdt.core.formatter.format_guardian_clause_on_one_line=false
org.eclipse.jdt.core.formatter.format_line_comment_starting_on_first_column=true
org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_annotation_declaration_header=true
org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_constant_header=true
org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_declaration_header=true
org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_record_header=true
org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_type_header=true
org.eclipse.jdt.core.formatter.indent_breaks_compare_to_cases=true
org.eclipse.jdt.core.formatter.indent_empty_lines=false
org.eclipse.jdt.core.formatter.indent_statements_compare_to_block=true
org.eclipse.jdt.core.formatter.indent_statements_compare_to_body=true
org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_cases=true
org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_switch=true
org.eclipse.jdt.core.formatter.indentation.size=4
org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_enum_constant=insert
org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_field=insert
org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_local_variable=insert
org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_method=insert
org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_package=insert
org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_parameter=do not insert
org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_type=insert
org.eclipse.jdt.core.formatter.insert_new_line_after_label=do not insert
org.eclipse.jdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer=do not insert
org.eclipse.jdt.core.formatter.insert_new_line_after_type_annotation=do not insert
org.eclipse.jdt.core.formatter.insert_new_line_at_end_of_file_if_missing=insert
org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement=do not insert
org.eclipse.jdt.core.formatter.insert_new_line_before_closing_brace_in_array_initializer=do not insert
org.eclipse.jdt.core.formatter.insert_new_line_before_else_in_if_statement=do not insert
org.eclipse.jdt.core.formatter.insert_new_line_before_finally_in_try_statement=do not insert
org.eclipse.jdt.core.formatter.insert_new_line_before_while_in_do_statement=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_additive_operator=insert
org.eclipse.jdt.core.formatter.insert_space_after_and_in_type_parameter=insert
org.eclipse.jdt.core.formatter.insert_space_after_arrow_in_switch_case=insert
org.eclipse.jdt.core.formatter.insert_space_after_arrow_in_switch_default=insert
org.eclipse.jdt.core.formatter.insert_space_after_assignment_operator=insert
org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation_type_declaration=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_bitwise_operator=insert
org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_parameters=insert
org.eclipse.jdt.core.formatter.insert_space_after_closing_brace_in_block=insert
org.eclipse.jdt.core.formatter.insert_space_after_closing_paren_in_cast=insert
org.eclipse.jdt.core.formatter.insert_space_after_colon_in_assert=insert
org.eclipse.jdt.core.formatter.insert_space_after_colon_in_case=insert
org.eclipse.jdt.core.formatter.insert_space_after_colon_in_conditional=insert
org.eclipse.jdt.core.formatter.insert_space_after_colon_in_for=insert
org.eclipse.jdt.core.formatter.insert_space_after_colon_in_labeled_statement=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_allocation_expression=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_annotation=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_array_initializer=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_parameters=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_throws=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_constant_arguments=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_declarations=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_explicitconstructorcall_arguments=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_increments=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_inits=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_parameters=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_throws=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_invocation_arguments=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_field_declarations=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_local_declarations=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_parameterized_type_reference=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_permitted_types=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_record_components=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_superinterfaces=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_switch_case_expressions=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_arguments=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_parameters=insert
org.eclipse.jdt.core.formatter.insert_space_after_ellipsis=insert
org.eclipse.jdt.core.formatter.insert_space_after_lambda_arrow=insert
org.eclipse.jdt.core.formatter.insert_space_after_logical_operator=insert
org.eclipse.jdt.core.formatter.insert_space_after_multiplicative_operator=insert
org.eclipse.jdt.core.formatter.insert_space_after_not_operator=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_parameterized_type_reference=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_arguments=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_parameters=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_brace_in_array_initializer=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_allocation_expression=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_reference=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_annotation=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_cast=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_catch=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_constructor_declaration=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_enum_constant=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_for=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_if=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_declaration=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_invocation=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_parenthesized_expression=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_record_declaration=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_switch=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_synchronized=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_try=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_while=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_postfix_operator=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_prefix_operator=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_question_in_conditional=insert
org.eclipse.jdt.core.formatter.insert_space_after_question_in_wildcard=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_relational_operator=insert
org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_for=insert
org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_try_resources=insert
org.eclipse.jdt.core.formatter.insert_space_after_shift_operator=insert
org.eclipse.jdt.core.formatter.insert_space_after_string_concatenation=insert
org.eclipse.jdt.core.formatter.insert_space_after_unary_operator=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_additive_operator=insert
org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter=insert
org.eclipse.jdt.core.formatter.insert_space_before_arrow_in_switch_case=insert
org.eclipse.jdt.core.formatter.insert_space_before_arrow_in_switch_default=insert
org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator=insert
org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration=insert
org.eclipse.jdt.core.formatter.insert_space_before_bitwise_operator=insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_parameterized_type_reference=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_arguments=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_parameters=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_brace_in_array_initializer=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_allocation_expression=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_reference=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_annotation=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_cast=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_catch=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_constructor_declaration=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_enum_constant=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_for=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_if=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_declaration=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_invocation=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_parenthesized_expression=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_record_declaration=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_switch=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_synchronized=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_try=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_while=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_colon_in_assert=insert
org.eclipse.jdt.core.formatter.insert_space_before_colon_in_case=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_colon_in_conditional=insert
org.eclipse.jdt.core.formatter.insert_space_before_colon_in_default=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_colon_in_for=insert
org.eclipse.jdt.core.formatter.insert_space_before_colon_in_labeled_statement=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_allocation_expression=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_annotation=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_array_initializer=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_parameters=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_throws=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_constant_arguments=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_declarations=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_explicitconstructorcall_arguments=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_increments=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_inits=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_parameters=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_throws=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_field_declarations=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_local_declarations=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_parameterized_type_reference=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_permitted_types=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_record_components=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_superinterfaces=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_switch_case_expressions=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_arguments=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_ellipsis=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_lambda_arrow=insert
org.eclipse.jdt.core.formatter.insert_space_before_logical_operator=insert
org.eclipse.jdt.core.formatter.insert_space_before_multiplicative_operator=insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_parameterized_type_reference=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_arguments=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_parameters=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_annotation_type_declaration=insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_anonymous_type_declaration=insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_array_initializer=insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_block=insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_constructor_declaration=insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_constant=insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_declaration=insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_method_declaration=insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_record_constructor=insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_record_declaration=insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_switch=insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_type_declaration=insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_allocation_expression=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_reference=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_type_reference=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation_type_member_declaration=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_catch=insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_constructor_declaration=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_enum_constant=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_for=insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_if=insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_declaration=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_invocation=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_parenthesized_expression=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_record_declaration=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_switch=insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_synchronized=insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_try=insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_while=insert
org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_return=insert
org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_throw=insert
org.eclipse.jdt.core.formatter.insert_space_before_postfix_operator=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_prefix_operator=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_question_in_conditional=insert
org.eclipse.jdt.core.formatter.insert_space_before_question_in_wildcard=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_relational_operator=insert
org.eclipse.jdt.core.formatter.insert_space_before_semicolon=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_for=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_try_resources=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_shift_operator=insert
org.eclipse.jdt.core.formatter.insert_space_before_string_concatenation=insert
org.eclipse.jdt.core.formatter.insert_space_before_unary_operator=do not insert
org.eclipse.jdt.core.formatter.insert_space_between_brackets_in_array_type_reference=do not insert
org.eclipse.jdt.core.formatter.insert_space_between_empty_braces_in_array_initializer=do not insert
org.eclipse.jdt.core.formatter.insert_space_between_empty_brackets_in_array_allocation_expression=do not insert
org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_annotation_type_member_declaration=do not insert
org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_constructor_declaration=do not insert
org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_enum_constant=do not insert
org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_declaration=do not insert
org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_invocation=do not insert
org.eclipse.jdt.core.formatter.join_lines_in_comments=true
org.eclipse.jdt.core.formatter.join_wrapped_lines=true
org.eclipse.jdt.core.formatter.keep_annotation_declaration_on_one_line=one_line_never
org.eclipse.jdt.core.formatter.keep_anonymous_type_declaration_on_one_line=one_line_if_empty
org.eclipse.jdt.core.formatter.keep_code_block_on_one_line=one_line_never
org.eclipse.jdt.core.formatter.keep_else_statement_on_same_line=false
org.eclipse.jdt.core.formatter.keep_empty_array_initializer_on_one_line=false
org.eclipse.jdt.core.formatter.keep_enum_constant_declaration_on_one_line=one_line_if_empty
org.eclipse.jdt.core.formatter.keep_enum_declaration_on_one_line=one_line_never
org.eclipse.jdt.core.formatter.keep_if_then_body_block_on_one_line=one_line_never
org.eclipse.jdt.core.formatter.keep_imple_if_on_one_line=false
org.eclipse.jdt.core.formatter.keep_lambda_body_block_on_one_line=one_line_never
org.eclipse.jdt.core.formatter.keep_loop_body_block_on_one_line=one_line_never
org.eclipse.jdt.core.formatter.keep_method_body_on_one_line=one_line_if_empty
org.eclipse.jdt.core.formatter.keep_record_constructor_on_one_line=one_line_if_empty
org.eclipse.jdt.core.formatter.keep_record_declaration_on_one_line=one_line_never
org.eclipse.jdt.core.formatter.keep_simple_do_while_body_on_same_line=false
org.eclipse.jdt.core.formatter.keep_simple_for_body_on_same_line=false
org.eclipse.jdt.core.formatter.keep_simple_getter_setter_on_one_line=false
org.eclipse.jdt.core.formatter.keep_simple_while_body_on_same_line=false
org.eclipse.jdt.core.formatter.keep_switch_body_block_on_one_line=one_line_never
org.eclipse.jdt.core.formatter.keep_switch_case_with_arrow_on_one_line=one_line_never
org.eclipse.jdt.core.formatter.keep_then_statement_on_same_line=false
org.eclipse.jdt.core.formatter.keep_type_declaration_on_one_line=one_line_never
org.eclipse.jdt.core.formatter.lineSplit=100
org.eclipse.jdt.core.formatter.never_indent_block_comments_on_first_column=false
org.eclipse.jdt.core.formatter.never_indent_line_comments_on_first_column=false
org.eclipse.jdt.core.formatter.number_of_blank_lines_after_code_block=0
org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_code_block=0
org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_method_body=0
org.eclipse.jdt.core.formatter.number_of_blank_lines_at_end_of_code_block=0
org.eclipse.jdt.core.formatter.number_of_blank_lines_at_end_of_method_body=0
org.eclipse.jdt.core.formatter.number_of_blank_lines_before_code_block=0
org.eclipse.jdt.core.formatter.number_of_empty_lines_to_preserve=3
org.eclipse.jdt.core.formatter.parentheses_positions_in_annotation=common_lines
org.eclipse.jdt.core.formatter.parentheses_positions_in_catch_clause=common_lines
org.eclipse.jdt.core.formatter.parentheses_positions_in_enum_constant_declaration=common_lines
org.eclipse.jdt.core.formatter.parentheses_positions_in_for_statment=common_lines
org.eclipse.jdt.core.formatter.parentheses_positions_in_if_while_statement=common_lines
org.eclipse.jdt.core.formatter.parentheses_positions_in_lambda_declaration=common_lines
org.eclipse.jdt.core.formatter.parentheses_positions_in_method_delcaration=common_lines
org.eclipse.jdt.core.formatter.parentheses_positions_in_method_invocation=common_lines
org.eclipse.jdt.core.formatter.parentheses_positions_in_record_declaration=common_lines
org.eclipse.jdt.core.formatter.parentheses_positions_in_switch_statement=common_lines
org.eclipse.jdt.core.formatter.parentheses_positions_in_try_clause=common_lines
org.eclipse.jdt.core.formatter.put_empty_statement_on_new_line=false
org.eclipse.jdt.core.formatter.tabulation.char=space
org.eclipse.jdt.core.formatter.tabulation.size=2
org.eclipse.jdt.core.formatter.text_block_indentation=0
org.eclipse.jdt.core.formatter.use_on_off_tags=true
org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations=false
org.eclipse.jdt.core.formatter.wrap_before_additive_operator=true
org.eclipse.jdt.core.formatter.wrap_before_assertion_message_operator=true
org.eclipse.jdt.core.formatter.wrap_before_assignment_operator=false
org.eclipse.jdt.core.formatter.wrap_before_bitwise_operator=true
org.eclipse.jdt.core.formatter.wrap_before_conditional_operator=true
org.eclipse.jdt.core.formatter.wrap_before_logical_operator=true
org.eclipse.jdt.core.formatter.wrap_before_multiplicative_operator=true
org.eclipse.jdt.core.formatter.wrap_before_or_operator_multicatch=true
org.eclipse.jdt.core.formatter.wrap_before_relational_operator=true
org.eclipse.jdt.core.formatter.wrap_before_shift_operator=true
org.eclipse.jdt.core.formatter.wrap_before_string_concatenation=true
org.eclipse.jdt.core.formatter.wrap_before_switch_case_arrow_operator=false
org.eclipse.jdt.core.formatter.wrap_outer_expressions_when_nested=true
org.eclipse.jdt.core.javaFormatter=org.eclipse.jdt.core.defaultJavaFormatter

View File

@@ -0,0 +1,3 @@
eclipse.preferences.version=1
formatter_profile=_GoogleStyle
formatter_settings_version=22

View File

@@ -4,15 +4,15 @@
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<artifactId>jackfruit</artifactId>
<artifactId>jackfruit-parent</artifactId>
<groupId>edu.jhuapl.ses.srn</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<artifactId>annotations</artifactId>
<artifactId>jackfruit</artifactId>
<name>annotations</name>
<description>Java configuration library using annotations</description>
<name>jackfruit</name>
<description>Java Annotations Configuration library</description>
<!-- Specifies organization -->
<organization>

View File

@@ -1,5 +1,12 @@
package jackfruit.annotations;
/**
* Interface to serialize/deserialize a string to a custom class.
*
* @author nairah1
*
* @param <T>
*/
public interface Parser<T> {
public T fromString(String s);

View File

@@ -6,7 +6,7 @@ import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Take a supplied String and turn it into an Object
* This class will convert a String to/from an Object
*
* @author nairah1
*

View File

@@ -0,0 +1,64 @@
package jackfruit.processor;
import java.util.List;
import java.util.Optional;
import javax.lang.model.type.TypeMirror;
import org.immutables.value.Value;
import jackfruit.annotations.Parser;
/**
* Holds annotation information and other metadata about an annotated method.
*
* @author nairah1
*
*/
@Value.Immutable
public abstract class AnnotationBundle {
/**
*
* @return the return type of this method without any parameters (e.g. return List rather than
* List<String>}
*/
public abstract TypeMirror erasure();
/**
*
* @return the parameterized types, if any of this method (e.g. return String if the annotated
* method returns List<String>)
*/
public abstract List<TypeMirror> typeArgs();
/**
* Comment for this configuration parameter. This can be blank.
*
* @return
*/
public abstract String comment();
/**
* Default value for this configuration parameter. This is required.
*
* @return
*/
public abstract String defaultValue();
/**
* Key used in the configuration file. If omitted, default value is the name of the configuration
* parameter (the method name).
*
* @return
*/
public abstract String key();
/**
* If this configuration parameter is not a string or primitive/boxed type, this class will
* convert the string to the proper object and vice versa. This class must implement
* {@link Parser}.
*
* @return
*/
public abstract Optional<TypeMirror> parserClass();
}

View File

@@ -0,0 +1,53 @@
package jackfruit.processor;
import org.apache.commons.configuration2.Configuration;
import org.apache.commons.configuration2.PropertiesConfiguration;
import org.apache.commons.configuration2.PropertiesConfigurationLayout;
/**
* This interface converts instances of annotated interfaces of type T to Apache Commons
* Configuration files and vice versa.
*
* @author nairah1
*
* @param <T>
*/
public interface ConfigFactory<T> {
/**
* This returns an object of type T with default values.
*
* @return
*/
T getTemplate();
/**
* This creates an object of type T from the supplied Apache Commons {@link Configuration}.
*
* @param config
* @return
*/
T fromConfig(Configuration config);
/**
* This creates an Apache Commons {@link PropertiesConfiguration} from the supplied object T.
*
* @param t
* @param layout used for formatting the returned PropertiesConfiguration
* @return
*/
PropertiesConfiguration toConfig(T t, PropertiesConfigurationLayout layout);
/**
* This creates an Apache Commons {@link PropertiesConfiguration} from the supplied object T. This
* is simply a call to {@link #toConfig(Object, PropertiesConfigurationLayout)} with a new
* PropertiesConfigurationLayout().
*
* @param t
* @return
*/
default PropertiesConfiguration toConfig(T t) {
return toConfig(t, new PropertiesConfigurationLayout());
}
}

View File

@@ -0,0 +1,518 @@
package jackfruit.processor;
import java.io.IOException;
import java.io.PrintWriter;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.Messager;
import javax.annotation.processing.Processor;
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.ElementKind;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.Modifier;
import javax.lang.model.element.PackageElement;
import javax.lang.model.element.TypeElement;
import javax.lang.model.type.DeclaredType;
import javax.lang.model.type.MirroredTypeException;
import javax.lang.model.type.TypeKind;
import javax.lang.model.type.TypeMirror;
import javax.lang.model.util.Types;
import javax.tools.Diagnostic;
import javax.tools.JavaFileObject;
import org.apache.commons.configuration2.Configuration;
import com.google.auto.service.AutoService;
import com.squareup.javapoet.ClassName;
import com.squareup.javapoet.JavaFile;
import com.squareup.javapoet.MethodSpec;
import com.squareup.javapoet.ParameterSpec;
import com.squareup.javapoet.ParameterizedTypeName;
import com.squareup.javapoet.TypeName;
import com.squareup.javapoet.TypeSpec;
import com.squareup.javapoet.TypeVariableName;
import jackfruit.annotations.Comment;
import jackfruit.annotations.DefaultValue;
import jackfruit.annotations.Jackfruit;
import jackfruit.annotations.Key;
import jackfruit.annotations.ParserClass;
/**
* https://www.javacodegeeks.com/2015/09/java-annotation-processors.html
*
* @author nairah1
*
*/
@SupportedSourceVersion(SourceVersion.RELEASE_17)
@SupportedAnnotationTypes("jackfruit.annotations.Jackfruit")
@AutoService(Processor.class)
public class ConfigProcessor extends AbstractProcessor {
@Override
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
List<Class<? extends Annotation>> supportedMethodAnnotations = new ArrayList<>();
supportedMethodAnnotations.add(Comment.class);
supportedMethodAnnotations.add(DefaultValue.class);
supportedMethodAnnotations.add(Key.class);
supportedMethodAnnotations.add(ParserClass.class);
Messager messager = processingEnv.getMessager();
List<Element> annotatedInterfaces = roundEnv.getElementsAnnotatedWith(Jackfruit.class).stream()
.filter(e -> e.getKind() == ElementKind.INTERFACE).collect(Collectors.toList());
for (Element element : annotatedInterfaces) {
try {
if (element instanceof TypeElement) {
TypeElement annotatedType = (TypeElement) element;
Jackfruit configParams = (Jackfruit) annotatedType.getAnnotation(Jackfruit.class);
String prefix = configParams.prefix();
if (prefix.length() > 0)
prefix += ".";
// This is the templatized class with annotations to be processed (e.g.
// ConfigTemplate)
TypeVariableName tvn = TypeVariableName.get(annotatedType.getSimpleName().toString());
// This is the generic class (e.g. ConfigFactory<ConfigTemplate>)
ParameterizedTypeName ptn = ParameterizedTypeName
.get(ClassName.get(jackfruit.processor.ConfigFactory.class), tvn);
// This is the name of the class to create (e.g. ConfigTemplateFactory)
String factoryName = String.format("%sFactory", annotatedType.getSimpleName());
TypeSpec.Builder classBuilder = TypeSpec.classBuilder(factoryName)
.addModifiers(Modifier.PUBLIC, Modifier.FINAL).addSuperinterface(ptn);
/*-
// logger for the generated class
FieldSpec loggerField = FieldSpec.builder(org.apache.logging.log4j.Logger.class, "logger")
.initializer("$T.getLogger()", org.apache.logging.log4j.LogManager.class)
.addModifiers(Modifier.PRIVATE, Modifier.FINAL, Modifier.STATIC).build();
classBuilder.addField(loggerField);
*/
// create a list of annotated methods
List<ExecutableElement> enclosedMethods = new ArrayList<>();
for (Element e : annotatedType.getEnclosedElements()) {
if (e.getKind() == ElementKind.METHOD && e instanceof ExecutableElement)
enclosedMethods.add((ExecutableElement) e);
}
// holds the annotation information on each method
Map<ExecutableElement, AnnotationBundle> annotationsMap = new LinkedHashMap<>();
for (ExecutableElement e : enclosedMethods) {
ImmutableAnnotationBundle.Builder builder = ImmutableAnnotationBundle.builder();
builder.key(e.getSimpleName().toString());
builder.comment("");
Types types = processingEnv.getTypeUtils();
TypeMirror returnType = e.getReturnType();
TypeMirror erasure = types.erasure(returnType);
builder.erasure(erasure);
List<TypeMirror> typeArgs = new ArrayList<>();
if (erasure.getKind() == TypeKind.DECLARED) {
// these are the parameter types for a List
List<? extends TypeMirror> args = ((DeclaredType) returnType).getTypeArguments();
typeArgs.addAll(args);
} else if (erasure.getKind().isPrimitive()) {
} else {
processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR,
String.format("Unsupported kind %s for type %s!", erasure.getKind().toString(),
erasure.toString()));
}
builder.addAllTypeArgs(typeArgs);
String defaultValue = null;
List<Annotation> methodAnnotations = new ArrayList<>();
for (var a : supportedMethodAnnotations)
methodAnnotations.add(e.getAnnotation(a));
for (Annotation annotation : methodAnnotations) {
if (annotation == null)
continue;
if (annotation instanceof Key) {
builder.key(((Key) annotation).value());
} else if (annotation instanceof Comment) {
builder.comment(((Comment) annotation).value());
} else if (annotation instanceof DefaultValue) {
DefaultValue d = (DefaultValue) annotation;
defaultValue = d.value();
} else if (annotation instanceof ParserClass) {
ParserClass pc = (ParserClass) annotation;
// this works, but there has to be a better way?
TypeMirror tm;
try {
// see
// https://stackoverflow.com/questions/7687829/java-6-annotation-processing-getting-a-class-from-an-annotation
tm = processingEnv.getElementUtils().getTypeElement(pc.value().toString())
.asType();
} catch (MirroredTypeException mte) {
tm = mte.getTypeMirror();
}
builder.parserClass(tm);
} else {
throw new IllegalArgumentException(
"Unknown annotation type " + annotation.getClass().getSimpleName());
}
}
// if a method does not have a default value, it will not be included in the generated
// code
if (defaultValue == null) {
messager.printMessage(Diagnostic.Kind.WARNING,
String.format("No default value on method %s!", e.getSimpleName()));
continue;
}
builder.defaultValue(defaultValue);
AnnotationBundle bundle = builder.build();
if (ConfigProcessorUtils.isList(bundle.erasure(), processingEnv)
&& bundle.typeArgs().size() == 0)
messager.printMessage(Diagnostic.Kind.ERROR,
String.format("No parameter type for List on method %s!", e.getSimpleName()));
annotationsMap.put(e, bundle);
}
// generate the methods from the interface
List<MethodSpec> methods = new ArrayList<>();
for (Method m : ConfigFactory.class.getMethods()) {
if (m.isDefault())
continue;
if (m.getName().equals("toConfig")) {
MethodSpec toConfig = buildToConfig(tvn, m, annotationsMap, prefix);
methods.add(toConfig);
}
if (m.getName().equals("getTemplate")) {
MethodSpec getTemplate = buildGetTemplate(tvn, m, annotationsMap, prefix);
methods.add(getTemplate);
}
if (m.getName().equals("fromConfig")) {
MethodSpec fromConfig = buildFromConfig(tvn, m, annotationsMap, prefix);
methods.add(fromConfig);
}
}
classBuilder.addMethods(methods);
TypeSpec thisClass = classBuilder.build();
// write the source code
PackageElement pkg = processingEnv.getElementUtils().getPackageOf(annotatedType);
JavaFileObject jfo =
processingEnv.getFiler().createSourceFile(pkg.getQualifiedName() + "." + factoryName);
JavaFile javaFile = JavaFile.builder(pkg.toString(), thisClass).build();
try (PrintWriter pw = new PrintWriter(jfo.openWriter())) {
javaFile.writeTo(pw);
}
messager.printMessage(Diagnostic.Kind.NOTE,
String.format("wrote %s", javaFile.toJavaFileObject().toUri()));
}
} catch (IOException e1) {
messager.printMessage(Diagnostic.Kind.ERROR, e1.getLocalizedMessage());
e1.printStackTrace();
}
}
return true;
}
/**
* Build the method to generate an Apache Commons {@link Configuration}
*
* @param tvn
* @param m
* @param annotationsMap
* @param prefix
* @return
*/
private MethodSpec buildToConfig(TypeVariableName tvn, Method m,
Map<ExecutableElement, AnnotationBundle> annotationsMap, String prefix) {
ParameterSpec ps = ParameterSpec.builder(tvn, "t").build();
ParameterSpec layout = ParameterSpec.builder(TypeVariableName.get(
org.apache.commons.configuration2.PropertiesConfigurationLayout.class.getCanonicalName()),
"layout").build();
MethodSpec.Builder methodBuilder =
MethodSpec.methodBuilder(m.getName()).addAnnotation(Override.class)
.addModifiers(Modifier.PUBLIC).returns(m.getGenericReturnType());
methodBuilder.addParameter(ps);
methodBuilder.addParameter(layout);
methodBuilder.addStatement("$T config = new $T()",
org.apache.commons.configuration2.PropertiesConfiguration.class,
org.apache.commons.configuration2.PropertiesConfiguration.class);
methodBuilder.addStatement("config.setLayout($N)", layout);
boolean needBlank = true;
for (ExecutableElement method : annotationsMap.keySet()) {
AnnotationBundle ab = annotationsMap.get(method);
String key = prefix + ab.key();
if (needBlank) {
methodBuilder.addStatement(String.format("$N.setBlancLinesBefore(\"%s\", 1)", key), layout);
needBlank = false;
}
TypeMirror parser = null;
String parserName = null;
if (ab.parserClass().isPresent()) {
parser = ab.parserClass().get();
parserName = method.getSimpleName() + "Parser";
methodBuilder.addStatement("$T " + parserName + " = new $T()", parser, parser);
}
if (ConfigProcessorUtils.isList(ab.erasure(), processingEnv)) {
// if it's a list, store a List<String> in the Apache configuration
TypeVariableName stringType = TypeVariableName.get(java.lang.String.class.getName());
ParameterizedTypeName listType =
ParameterizedTypeName.get(ClassName.get(java.util.List.class), stringType);
ParameterizedTypeName arrayListType =
ParameterizedTypeName.get(ClassName.get(java.util.ArrayList.class), stringType);
String listName = method.getSimpleName() + "List";
methodBuilder.addStatement("$T " + listName + " = new $T()", listType, arrayListType);
methodBuilder
.beginControlFlow(String.format("for (var element : t.%s())", method.getSimpleName()));
if (ab.parserClass().isPresent()) {
methodBuilder
.addStatement(String.format("%s.add(%s.toString(element))", listName, parserName));
} else {
methodBuilder
.addStatement(String.format("%s.add(String.format(\"%%s\", element))", listName));
}
methodBuilder.endControlFlow();
methodBuilder.addStatement(String.format("config.setProperty(\"%s\", %s)", key, listName));
} else {
if (ab.parserClass().isPresent()) {
// store the serialized string as the property
methodBuilder
.addStatement(String.format("config.setProperty(\"%s\", %s.toString($N.%s()))", key,
parserName, method.getSimpleName()), ps);
} else {
methodBuilder.addStatement(
String.format("config.setProperty(\"%s\", t.%s())", key, method.getSimpleName()));
}
}
// add the comment
if (ab.comment().length() > 0)
methodBuilder.addStatement(
String.format("$N.setComment(\"%s\", \"%s\")", key, ab.comment()), layout);
}
methodBuilder.addCode("return config;");
return methodBuilder.build();
}
private MethodSpec buildGetTemplate(TypeVariableName tvn, Method m,
Map<ExecutableElement, AnnotationBundle> annotationsMap, String prefix) {
// this builds the getTemplate() method
MethodSpec.Builder methodBuilder = MethodSpec.methodBuilder(m.getName())
.addAnnotation(Override.class).addModifiers(Modifier.PUBLIC).returns(tvn);
TypeSpec.Builder typeBuilder = TypeSpec.anonymousClassBuilder("").addSuperinterface(tvn);
for (ExecutableElement method : annotationsMap.keySet()) {
AnnotationBundle bundle = annotationsMap.get(method);
// this builds the method on the anonymous class
MethodSpec.Builder builder = MethodSpec.methodBuilder(method.getSimpleName().toString())
.addModifiers(Modifier.PUBLIC).addAnnotation(Override.class)
.returns(TypeName.get(method.getReturnType())).addJavadoc(bundle.comment());
TypeMirror parser = null;
String parserName = null;
if (bundle.parserClass().isPresent()) {
parser = bundle.parserClass().get();
parserName = method.getSimpleName() + "Parser";
builder.addStatement(String.format("$T %s = new $T()", parserName), parser, parser);
}
if (ConfigProcessorUtils.isList(bundle.erasure(), processingEnv)) {
TypeName argType = TypeName.get(bundle.typeArgs().get(0));
ParameterizedTypeName listType =
ParameterizedTypeName.get(ClassName.get(java.util.List.class), argType);
ParameterizedTypeName arrayListType =
ParameterizedTypeName.get(ClassName.get(java.util.ArrayList.class), argType);
String listName = method.getSimpleName() + "List";
builder.addStatement("$T " + listName + " = new $T()", listType, arrayListType);
builder.addStatement(
String.format("String [] parts = \"%s\".split(\"\\\\s+\")", bundle.defaultValue()));
builder.beginControlFlow("for (String part : parts)");
if (bundle.parserClass().isPresent()) {
builder.addStatement(String.format("%s.add(%s.fromString(part))", listName, parserName));
} else {
TypeMirror typeArg = bundle.typeArgs().get(0);
if (ConfigProcessorUtils.isByte(typeArg, processingEnv))
builder.addStatement(String.format("%s.add($T.valueOf(part))", listName),
java.lang.Byte.class);
if (ConfigProcessorUtils.isBoolean(typeArg, processingEnv))
builder.addStatement(String.format("%s.add($T.valueOf(part))", listName),
java.lang.Boolean.class);
if (ConfigProcessorUtils.isDouble(typeArg, processingEnv))
builder.addStatement(String.format("%s.add($T.valueOf(part))", listName),
java.lang.Double.class);
if (ConfigProcessorUtils.isFloat(typeArg, processingEnv))
builder.addStatement(String.format("%s.add($T.valueOf(part))", listName),
java.lang.Float.class);
if (ConfigProcessorUtils.isInteger(typeArg, processingEnv))
builder.addStatement(String.format("%s.add($T.valueOf(part))", listName),
java.lang.Integer.class);
if (ConfigProcessorUtils.isLong(typeArg, processingEnv))
builder.addStatement(String.format("%s.add($T.valueOf(part))", listName),
java.lang.Long.class);
if (ConfigProcessorUtils.isShort(typeArg, processingEnv))
builder.addStatement(String.format("%s.add($T.valueOf(part))", listName),
java.lang.Short.class);
if (ConfigProcessorUtils.isString(typeArg, processingEnv))
builder.addStatement(String.format("%s.add(part)", listName));
}
builder.endControlFlow();
builder.addStatement(String.format("return %s", listName));
} else {
if (bundle.parserClass().isPresent()) {
builder.addStatement(
String.format("return %s.fromString(\"%s\")", parserName, bundle.defaultValue()));
} else {
if (ConfigProcessorUtils.isString(bundle.erasure(), processingEnv)) {
builder.addStatement(String.format("return \"%s\"", bundle.defaultValue()));
} else {
builder.addStatement(String.format("return %s", bundle.defaultValue()));
}
}
}
typeBuilder.addMethod(builder.build());
}
methodBuilder.addStatement("return $L", typeBuilder.build());
return methodBuilder.build();
}
private MethodSpec buildFromConfig(TypeVariableName tvn, Method m,
Map<ExecutableElement, AnnotationBundle> annotationsMap, String prefix) {
MethodSpec.Builder methodBuilder = MethodSpec.methodBuilder(m.getName())
.addAnnotation(Override.class).addModifiers(Modifier.PUBLIC).returns(tvn)
.addParameter(org.apache.commons.configuration2.Configuration.class, "config");
TypeSpec.Builder typeBuilder = TypeSpec.anonymousClassBuilder("").addSuperinterface(tvn);
for (ExecutableElement method : annotationsMap.keySet()) {
AnnotationBundle bundle = annotationsMap.get(method);
MethodSpec.Builder builder = MethodSpec.methodBuilder(method.getSimpleName().toString())
.addModifiers(Modifier.PUBLIC).addAnnotation(Override.class)
.returns(TypeName.get(method.getReturnType())).addJavadoc(bundle.comment());
TypeMirror parser = null;
String parserName = null;
if (bundle.parserClass().isPresent()) {
parser = bundle.parserClass().get();
parserName = method.getSimpleName() + "Parser";
builder.addStatement(String.format("$T %s = new $T()", parserName), parser, parser);
}
if (ConfigProcessorUtils.isList(bundle.erasure(), processingEnv)) {
TypeName argType = TypeName.get(bundle.typeArgs().get(0));
ParameterizedTypeName listType =
ParameterizedTypeName.get(ClassName.get(java.util.List.class), argType);
ParameterizedTypeName arrayListType =
ParameterizedTypeName.get(ClassName.get(java.util.ArrayList.class), argType);
String listName = method.getSimpleName() + "List";
builder.addStatement("$T " + listName + " = new $T()", listType, arrayListType);
builder.addStatement(String.format("String [] parts = config.getStringArray(\"%s\")",
prefix + bundle.key()));
builder.beginControlFlow("for (String part : parts)");
if (bundle.parserClass().isPresent()) {
builder.addStatement(String.format("%s.add(%s.fromString(part))", listName, parserName));
} else {
TypeMirror typeArg = bundle.typeArgs().get(0);
if (ConfigProcessorUtils.isByte(typeArg, processingEnv))
builder.addStatement(String.format("%s.add($T.valueOf(part))", listName),
java.lang.Byte.class);
if (ConfigProcessorUtils.isBoolean(typeArg, processingEnv))
builder.addStatement(String.format("%s.add($T.valueOf(part))", listName),
java.lang.Boolean.class);
if (ConfigProcessorUtils.isDouble(typeArg, processingEnv))
builder.addStatement(String.format("%s.add($T.valueOf(part))", listName),
java.lang.Double.class);
if (ConfigProcessorUtils.isFloat(typeArg, processingEnv))
builder.addStatement(String.format("%s.add($T.valueOf(part))", listName),
java.lang.Float.class);
if (ConfigProcessorUtils.isInteger(typeArg, processingEnv))
builder.addStatement(String.format("%s.add($T.valueOf(part))", listName),
java.lang.Integer.class);
if (ConfigProcessorUtils.isLong(typeArg, processingEnv))
builder.addStatement(String.format("%s.add($T.valueOf(part))", listName),
java.lang.Long.class);
if (ConfigProcessorUtils.isShort(typeArg, processingEnv))
builder.addStatement(String.format("%s.add($T.valueOf(part))", listName),
java.lang.Short.class);
if (ConfigProcessorUtils.isString(typeArg, processingEnv))
builder.addStatement(String.format("%s.add(part)", listName));
}
builder.endControlFlow();
builder.addStatement(String.format("return %s", listName));
} else {
if (bundle.parserClass().isPresent()) {
builder.addStatement(String.format("return %s.fromString(config.getString(\"%s\"))",
parserName, prefix + bundle.key()));
} else {
if (ConfigProcessorUtils.isBoolean(bundle.erasure(), processingEnv)) {
builder.addStatement(
String.format("return config.getBoolean(\"%s\")", prefix + bundle.key()));
} else if (ConfigProcessorUtils.isByte(bundle.erasure(), processingEnv)) {
builder.addStatement(
String.format("return config.getByte(\"%s\")", prefix + bundle.key()));
} else if (ConfigProcessorUtils.isDouble(bundle.erasure(), processingEnv)) {
builder.addStatement(
String.format("return config.getDouble(\"%s\")", prefix + bundle.key()));
} else if (ConfigProcessorUtils.isFloat(bundle.erasure(), processingEnv)) {
builder.addStatement(
String.format("return config.getFloat(\"%s\")", prefix + bundle.key()));
} else if (ConfigProcessorUtils.isInteger(bundle.erasure(), processingEnv)) {
builder
.addStatement(String.format("return config.getInt(\"%s\")", prefix + bundle.key()));
} else if (ConfigProcessorUtils.isLong(bundle.erasure(), processingEnv)) {
builder.addStatement(
String.format("return config.getLong(\"%s\")", prefix + bundle.key()));
} else if (ConfigProcessorUtils.isShort(bundle.erasure(), processingEnv)) {
builder.addStatement(
String.format("return config.getShort(\"%s\")", prefix + bundle.key()));
} else if (ConfigProcessorUtils.isString(bundle.erasure(), processingEnv)) {
builder.addStatement(
String.format("return config.getString(\"%s\")", prefix + bundle.key()));
} else {
processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR,
"Can't handle return type " + m.getReturnType().getCanonicalName());
}
}
}
typeBuilder.addMethod(builder.build());
}
methodBuilder.addStatement("return $L", typeBuilder.build());
return methodBuilder.build();
}
}

View File

@@ -0,0 +1,132 @@
package jackfruit.processor;
import java.util.List;
import javax.annotation.processing.ProcessingEnvironment;
import javax.lang.model.type.TypeKind;
import javax.lang.model.type.TypeMirror;
import javax.lang.model.util.Elements;
import javax.lang.model.util.Types;
import javax.tools.Diagnostic;
public class ConfigProcessorUtils {
/**
*
* @param processingEnv
* @return true if this annotated member returns a {@link List}
*/
public final static boolean isList(TypeMirror typeMirror, ProcessingEnvironment processingEnv) {
return isClass(typeMirror, processingEnv, java.util.List.class);
}
/**
*
* @param typeMirror either {@link #erasure()} for the return value, or an element of
* {@link #typeArgs()} for a parameterized type
* @param processingEnv
* @return true if this annotated member returns a {@link Boolean} or primitive boolean
*/
public final static boolean isBoolean(TypeMirror typeMirror,
ProcessingEnvironment processingEnv) {
return isClass(typeMirror, processingEnv, java.lang.Boolean.class)
|| typeMirror.getKind() == TypeKind.BOOLEAN;
}
/**
*
* @param typeMirror either {@link #erasure()} for the return value, or an element of
* {@link #typeArgs()} for a parameterized type
* @param processingEnv
* @return true if this annotated member returns a {@link Byte} or primitive byte
*/
public final static boolean isByte(TypeMirror typeMirror, ProcessingEnvironment processingEnv) {
return isClass(typeMirror, processingEnv, java.lang.Byte.class)
|| typeMirror.getKind() == TypeKind.BYTE;
}
/**
*
* @param typeMirror either {@link #erasure()} for the return value, or an element of
* {@link #typeArgs()} for a parameterized type
* @param processingEnv
* @return true if this annotated member returns a {@link Double} or primitive double
*/
public final static boolean isDouble(TypeMirror typeMirror, ProcessingEnvironment processingEnv) {
return isClass(typeMirror, processingEnv, java.lang.Double.class)
|| typeMirror.getKind() == TypeKind.DOUBLE;
}
/**
*
* @param typeMirror either {@link #erasure()} for the return value, or an element of
* {@link #typeArgs()} for a parameterized type
* @param processingEnv
* @return true if this annotated member returns a {@link Float} or primitive float
*/
public final static boolean isFloat(TypeMirror typeMirror, ProcessingEnvironment processingEnv) {
return isClass(typeMirror, processingEnv, java.lang.Float.class)
|| typeMirror.getKind() == TypeKind.FLOAT;
}
/**
*
* @param typeMirror either {@link #erasure()} for the return value, or an element of
* {@link #typeArgs()} for a parameterized type
* @param processingEnv
* @return true if this annotated member returns a {@link Integer} or primitive int
*/
public final static boolean isInteger(TypeMirror typeMirror,
ProcessingEnvironment processingEnv) {
return isClass(typeMirror, processingEnv, java.lang.Integer.class)
|| typeMirror.getKind() == TypeKind.INT;
}
/**
*
* @param typeMirror either {@link #erasure()} for the return value, or an element of
* {@link #typeArgs()} for a parameterized type
* @param processingEnv
* @return true if this annotated member returns a {@link Long} or primitive long
*/
public final static boolean isLong(TypeMirror typeMirror, ProcessingEnvironment processingEnv) {
return isClass(typeMirror, processingEnv, java.lang.Long.class)
|| typeMirror.getKind() == TypeKind.LONG;
}
/**
*
* @param typeMirror either {@link #erasure()} for the return value, or an element of
* {@link #typeArgs()} for a parameterized type
* @param processingEnv
* @return true if this annotated member returns a {@link Short} or primitive float
*/
public final static boolean isShort(TypeMirror typeMirror, ProcessingEnvironment processingEnv) {
return isClass(typeMirror, processingEnv, java.lang.Short.class)
|| typeMirror.getKind() == TypeKind.SHORT;
}
/**
*
* @param typeMirror either {@link #erasure()} for the return value, or an element of
* {@link #typeArgs()} for a parameterized type
* @param processingEnv
* @return true if this annotated member returns a {@link String}
*/
public final static boolean isString(TypeMirror typeMirror, ProcessingEnvironment processingEnv) {
return isClass(typeMirror, processingEnv, java.lang.String.class);
}
private final static boolean isClass(TypeMirror typeMirror, ProcessingEnvironment processingEnv,
Class<?> compareTo) {
Elements elements = processingEnv.getElementUtils();
Types types = processingEnv.getTypeUtils();
if (elements.getTypeElement(compareTo.getCanonicalName()) == null) {
processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR,
String.format("Cannot recognize %s\n", compareTo.getCanonicalName()));
}
return types.isSubtype(typeMirror,
types.erasure(elements.getTypeElement(compareTo.getCanonicalName()).asType()));
}
}

172
pom.xml
View File

@@ -1,215 +1,93 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<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/xsd/maven-4.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/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>edu.jhuapl.ses.srn</groupId>
<artifactId>jackfruit</artifactId>
<artifactId>jackfruit-parent</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>pom</packaging>
<name>jackfruit</name>
<!-- FIXME change it to the project's website -->
<url>http://www.example.com</url>
<name>jackfruit-parent</name>
<!-- publish to surfshop -->
<distributionManagement>
<repository>
<id>central</id>
<name>surfshop-snapshots</name>
<url>http://surfshop.jhuapl.edu:8081/artifactory/libs-snapshot-local</url>
</repository>
</distributionManagement>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<pluginManagement>
<!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) -->
<plugins>
<!-- clean lifecycle, see https://maven.apache.org/ref/current/maven-core/lifecycles.html#clean_Lifecycle -->
<plugin>
<artifactId>maven-clean-plugin</artifactId>
<version>3.1.0</version>
</plugin>
<!-- default lifecycle, jar packaging: see https://maven.apache.org/ref/current/maven-core/default-bindings.html#Plugin_bindings_for_jar_packaging -->
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<version>3.0.2</version>
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.0</version>
<configuration>
<showWarnings>true</showWarnings>
</configuration>
</plugin>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.22.1</version>
</plugin>
<plugin>
<artifactId>maven-jar-plugin</artifactId>
<version>3.0.2</version>
</plugin>
<plugin>
<artifactId>maven-install-plugin</artifactId>
<version>2.5.2</version>
</plugin>
<plugin>
<artifactId>maven-deploy-plugin</artifactId>
<version>2.8.2</version>
</plugin>
<!-- site lifecycle, see https://maven.apache.org/ref/current/maven-core/lifecycles.html#site_Lifecycle -->
<plugin>
<artifactId>maven-site-plugin</artifactId>
<version>3.7.1</version>
</plugin>
<plugin>
<artifactId>maven-project-info-reports-plugin</artifactId>
<version>3.0.0</version>
</plugin>
</plugins>
</pluginManagement>
</build>
<modules>
<module>annotations</module>
<module>jackfruit</module>
<module>demo</module>
</modules>
</project>