mirror of
https://github.com/JHUAPL/Jackfruit.git
synced 2026-01-08 21:58:09 -05:00
Merge branch '11-add-createconfig' into 'main'
Resolve "Add createConfig" Closes #11 See merge request nairah1/jackfruit!11
This commit is contained in:
34
README.md
34
README.md
@@ -143,20 +143,9 @@ The `@Jackfruit` annotation goes on the abstract type. The remaining annotation
|
||||
### Jackfruit
|
||||
This annotation goes on the abstract type to signify that it should be run through the annotation processor. There is an optional "prefix" argument that can be used to add a prefix to all of the configuration keys created by the processor. The Jackfruit annotation is not inherited by derived classes.
|
||||
|
||||
Every Factory class has a default constructor with this prefix (or an empty string if no prefix is specified) and a constructor where a prefix may be supplied. This is useful in case the user wants to create many configurations with the same parameters but different prefixes. The DemoInterface example above generates the following Factory code:
|
||||
```
|
||||
private final String prefix;
|
||||
Every Factory class has a default constructor with this prefix (or an empty string if no prefix is specified) and a constructor where a prefix may be supplied. This is useful in case the user wants to create many configurations with the same parameters but different prefixes.
|
||||
|
||||
public DemoInterfaceFactory() {
|
||||
this.prefix = "prefix.";
|
||||
}
|
||||
|
||||
public DemoInterfaceFactory(String prefix) {
|
||||
if (prefix.length() > 0) prefix += ".";
|
||||
this.prefix = prefix;
|
||||
}
|
||||
```
|
||||
You can use the same set of parameters with a different prefix:
|
||||
To use the same set of parameters with a different prefix:
|
||||
```
|
||||
DemoInterfaceFactory factory = new DemoInterfaceFactory("anotherPrefix");
|
||||
```
|
||||
@@ -184,3 +173,22 @@ public interface Parser<T> {
|
||||
public String toString(T t);
|
||||
}
|
||||
```
|
||||
|
||||
## Modifying a configuration
|
||||
|
||||
If you'd like to create a configuration object that differs from the template populated with default values or one you've loaded from a file, the factory has "with" methods that will return a new PropertiesConfiguration object with a value replaced. For example:
|
||||
|
||||
```
|
||||
DemoInterfaceFactory factory = new DemoInterfaceFactory();
|
||||
DemoInterface template = factory.getTemplate();
|
||||
PropertiesConfiguration config = factory.toConfig(template);
|
||||
// add 999 to the default double values
|
||||
List<Double> doubles = template.doubles();
|
||||
doubles.add(999.);
|
||||
config = factory.withDoubles(config, doubles);
|
||||
config = factory.withIntMethod(config, 4);
|
||||
```
|
||||
|
||||
This replaces the "doubles" and the "key" properties. The "with" methods are just wrappers around the "setProperty" method of the PropertiesConfiguration class.
|
||||
|
||||
|
||||
|
||||
@@ -6,6 +6,38 @@ import jackfruit.annotations.DefaultValue;
|
||||
import jackfruit.annotations.Jackfruit;
|
||||
import jackfruit.annotations.ParserClass;
|
||||
|
||||
/**
|
||||
* @Jackfruit on abstract class
|
||||
* <ul>
|
||||
* <li>prefix is optional</li>
|
||||
* </ul>
|
||||
* Method annotations:
|
||||
* <ul>
|
||||
* <li>@Key
|
||||
* <ul>
|
||||
* <li>If omitted value is method name</li>
|
||||
* </ul>
|
||||
* </li>
|
||||
* <li>@Comment
|
||||
* <ul>
|
||||
* <li>Optional</li>
|
||||
* </ul>
|
||||
* </li>
|
||||
* <li>@DefaultValue
|
||||
* <ul>
|
||||
* <li>Required, String value</li>
|
||||
* </ul>
|
||||
* </li>
|
||||
* <li>@Parser
|
||||
* <ul>
|
||||
* <li>Optional, name of class to create object from String using its fromString() method</li>
|
||||
* </ul>
|
||||
* <p>
|
||||
* Inspired by <a href="http://owner.aeonbits.org/">owner</a>.
|
||||
*
|
||||
* @author nairah1
|
||||
*
|
||||
*/
|
||||
@Jackfruit(prefix = "prefix")
|
||||
public abstract class DemoClass extends DemoSuperClass {
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ import jackfruit.annotations.Key;
|
||||
import jackfruit.annotations.ParserClass;
|
||||
|
||||
/**
|
||||
* @Configurable on interface
|
||||
* @Jackfruit on interface
|
||||
* <ul>
|
||||
* <li>prefix is optional</li>
|
||||
* </ul>
|
||||
|
||||
@@ -6,7 +6,7 @@ import jackfruit.annotations.Jackfruit;
|
||||
import jackfruit.annotations.ParserClass;
|
||||
|
||||
// prefix can be superseded by inherited classes
|
||||
@Jackfruit
|
||||
@Jackfruit(prefix = "super ")
|
||||
public abstract class DemoSuperClass extends DemoSuperSuperClass {
|
||||
|
||||
@Comment("from DemoSuperClass")
|
||||
|
||||
@@ -5,7 +5,7 @@ import jackfruit.annotations.DefaultValue;
|
||||
import jackfruit.annotations.Jackfruit;
|
||||
import jackfruit.annotations.Key;
|
||||
|
||||
@Jackfruit
|
||||
@Jackfruit(prefix = "super.super.")
|
||||
public abstract class DemoSuperSuperClass {
|
||||
|
||||
@Comment("from DemoSuperSuperClass")
|
||||
|
||||
@@ -36,6 +36,11 @@ public class JackfruitDemo {
|
||||
System.out.println("*** This is the template, with default values ***");
|
||||
config.write(new PrintWriter(System.out));
|
||||
|
||||
// add 999 to the default double values
|
||||
List<Double> doubles = template.doubles();
|
||||
doubles.add(999.);
|
||||
config = factory.withDoubles(config, doubles);
|
||||
|
||||
// write to file
|
||||
File tmpFile = File.createTempFile("tmp", ".config");
|
||||
tmpFile.deleteOnExit();
|
||||
@@ -43,6 +48,7 @@ public class JackfruitDemo {
|
||||
config.write(new PrintWriter(tmpFile));
|
||||
|
||||
System.out.println("\n*** This is the configuration read from " + tmpFile.getAbsolutePath());
|
||||
System.out.println("*** Note 999 has been added to doubles");
|
||||
// read from file
|
||||
config = new Configurations().properties(tmpFile);
|
||||
|
||||
@@ -65,8 +71,9 @@ public class JackfruitDemo {
|
||||
// create a new factory with a different prefix, but same parameters
|
||||
factory = new DemoClassFactory("anotherPrefix");
|
||||
template = factory.fromConfig(config);
|
||||
|
||||
// this will not find anything
|
||||
|
||||
// this will not find anything, since template was created from the original config, which
|
||||
// uses the original prefix.
|
||||
randoms = template.randoms();
|
||||
for (SomeRandomClass random : randoms)
|
||||
System.out.println("random.toUpperCase() = " + random.toUpperCase());
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
<maven-compiler-plugin.version>
|
||||
3.10.1
|
||||
</maven-compiler-plugin.version>
|
||||
<log4j-version>2.19.0</log4j-version>
|
||||
<immutables.version>2.9.2</immutables.version>
|
||||
</properties>
|
||||
|
||||
@@ -53,17 +54,17 @@
|
||||
<dependency>
|
||||
<groupId>org.apache.logging.log4j</groupId>
|
||||
<artifactId>log4j-api</artifactId>
|
||||
<version>2.18.0</version>
|
||||
<version>${log4j-version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.logging.log4j</groupId>
|
||||
<artifactId>log4j-core</artifactId>
|
||||
<version>2.18.0</version>
|
||||
<version>${log4j-version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-configuration2</artifactId>
|
||||
<version>2.0</version>
|
||||
<version>2.8.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.immutables</groupId>
|
||||
@@ -122,5 +123,24 @@
|
||||
</plugin>
|
||||
</plugins>
|
||||
</pluginManagement>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>exec-maven-plugin</artifactId>
|
||||
<version>3.0.0</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<phase>generate-sources</phase>
|
||||
<id>createVersionFile</id>
|
||||
<goals>
|
||||
<goal>exec</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<executable>${project.basedir}/src/main/bash/createVersionFile.bash</executable>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
|
||||
33
jackfruit/src/main/bash/createVersionFile.bash
Executable file
33
jackfruit/src/main/bash/createVersionFile.bash
Executable file
@@ -0,0 +1,33 @@
|
||||
#!/bin/bash
|
||||
|
||||
# This script is run from maven. See the exec-maven-plugin block in the pom.xml file.
|
||||
|
||||
cd $(dirname $0)
|
||||
|
||||
rev=$(git rev-parse --verify --short HEAD)
|
||||
if [ $? -gt 0 ]; then
|
||||
rev="UNKNOWN"
|
||||
fi
|
||||
|
||||
branch=$(git symbolic-ref --short HEAD)
|
||||
if [ $? -gt 0 ]; then
|
||||
branch="UNKNOWN"
|
||||
fi
|
||||
|
||||
package=Jackfruit
|
||||
srcFile="../java/jackfruit/JackfruitVersion.java"
|
||||
mkdir -p $(dirname $srcFile)
|
||||
|
||||
touch $srcFile
|
||||
|
||||
cat <<EOF > $srcFile
|
||||
|
||||
package jackfruit;
|
||||
|
||||
public class JackfruitVersion {
|
||||
public final static String rev = new String("$rev");
|
||||
public final static String packageName = new String("$package");
|
||||
public final static String branch = new String("$branch");
|
||||
}
|
||||
|
||||
EOF
|
||||
9
jackfruit/src/main/java/jackfruit/JackfruitVersion.java
Normal file
9
jackfruit/src/main/java/jackfruit/JackfruitVersion.java
Normal file
@@ -0,0 +1,9 @@
|
||||
|
||||
package jackfruit;
|
||||
|
||||
public class JackfruitVersion {
|
||||
public final static String rev = new String("168ca45");
|
||||
public final static String packageName = new String("Jackfruit");
|
||||
public final static String branch = new String("11-add-createconfig");
|
||||
}
|
||||
|
||||
@@ -4,6 +4,8 @@ import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.Method;
|
||||
import java.time.OffsetDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashMap;
|
||||
@@ -12,6 +14,7 @@ import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
import javax.annotation.processing.AbstractProcessor;
|
||||
import javax.annotation.processing.Generated;
|
||||
import javax.annotation.processing.Messager;
|
||||
import javax.annotation.processing.Processor;
|
||||
import javax.annotation.processing.RoundEnvironment;
|
||||
@@ -34,6 +37,7 @@ import javax.tools.Diagnostic;
|
||||
import javax.tools.JavaFileObject;
|
||||
import org.apache.commons.configuration2.Configuration;
|
||||
import com.google.auto.service.AutoService;
|
||||
import com.squareup.javapoet.AnnotationSpec;
|
||||
import com.squareup.javapoet.ClassName;
|
||||
import com.squareup.javapoet.JavaFile;
|
||||
import com.squareup.javapoet.MethodSpec;
|
||||
@@ -42,6 +46,7 @@ import com.squareup.javapoet.ParameterizedTypeName;
|
||||
import com.squareup.javapoet.TypeName;
|
||||
import com.squareup.javapoet.TypeSpec;
|
||||
import com.squareup.javapoet.TypeVariableName;
|
||||
import jackfruit.JackfruitVersion;
|
||||
import jackfruit.annotations.Comment;
|
||||
import jackfruit.annotations.DefaultValue;
|
||||
import jackfruit.annotations.Jackfruit;
|
||||
@@ -94,8 +99,8 @@ public class ConfigProcessor extends AbstractProcessor {
|
||||
TypeElement annotatedType = (TypeElement) element;
|
||||
|
||||
Jackfruit configParams = (Jackfruit) annotatedType.getAnnotation(Jackfruit.class);
|
||||
String prefix = configParams.prefix();
|
||||
if (prefix.length() > 0)
|
||||
String prefix = configParams.prefix().strip();
|
||||
if (prefix.length() > 0 && !prefix.endsWith("."))
|
||||
prefix += ".";
|
||||
|
||||
// This is the templatized class with annotations to be processed (e.g.
|
||||
@@ -109,8 +114,19 @@ public class ConfigProcessor extends AbstractProcessor {
|
||||
// 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);
|
||||
OffsetDateTime now = OffsetDateTime.now();
|
||||
DateTimeFormatter formatter = DateTimeFormatter.ISO_OFFSET_DATE_TIME;
|
||||
|
||||
AnnotationSpec generated = AnnotationSpec.builder(Generated.class)
|
||||
.addMember("value", String.format("\"%s\"", JackfruitVersion.packageName))
|
||||
.addMember("date", String.format("\"%s\"", formatter.format(now)))
|
||||
.addMember("comments", String.format("\"branch %s (%s)\"", JackfruitVersion.branch,
|
||||
JackfruitVersion.rev))
|
||||
.build();
|
||||
|
||||
TypeSpec.Builder classBuilder =
|
||||
TypeSpec.classBuilder(factoryName).addModifiers(Modifier.PUBLIC, Modifier.FINAL)
|
||||
.addSuperinterface(ptn).addAnnotation(generated);
|
||||
/*-
|
||||
// logger for the generated class
|
||||
FieldSpec loggerField = FieldSpec.builder(org.apache.logging.log4j.Logger.class, "logger")
|
||||
@@ -171,11 +187,15 @@ public class ConfigProcessor extends AbstractProcessor {
|
||||
classBuilder.addMethod(constructor);
|
||||
|
||||
// add a constructor where caller can set prefix
|
||||
constructor = MethodSpec.constructorBuilder().addModifiers(Modifier.PUBLIC)
|
||||
.addParameter(String.class, prefixMemberName)
|
||||
.addStatement("if ($N.length() > 0) $N += $S", prefixMemberName, prefixMemberName,
|
||||
".")
|
||||
.addStatement("this.$N = $N", prefixMemberName, prefixMemberName).build();
|
||||
constructor =
|
||||
MethodSpec.constructorBuilder().addModifiers(Modifier.PUBLIC)
|
||||
.addParameter(String.class, prefixMemberName)
|
||||
.beginControlFlow("if ($N == null)", prefixMemberName)
|
||||
.addStatement("$N = \"\"", prefixMemberName).endControlFlow()
|
||||
.addStatement("$N = $N.strip()", prefixMemberName, prefixMemberName)
|
||||
.addStatement("if (!$N.endsWith(\".\")) $N += $S", prefixMemberName,
|
||||
prefixMemberName, ".")
|
||||
.addStatement("this.$N = $N", prefixMemberName, prefixMemberName).build();
|
||||
classBuilder.addMethod(constructor);
|
||||
|
||||
// generate the methods from the interface
|
||||
@@ -201,6 +221,9 @@ public class ConfigProcessor extends AbstractProcessor {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
methods.addAll(buildWithMethods(tvn, annotationsMap, prefixMemberName));
|
||||
|
||||
classBuilder.addMethods(methods);
|
||||
TypeSpec thisClass = classBuilder.build();
|
||||
|
||||
@@ -306,7 +329,7 @@ public class ConfigProcessor extends AbstractProcessor {
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the method to generate an Apache Commons {@link Configuration}
|
||||
* Build the method to generate an Apache Commons {@link Configuration} from an object
|
||||
*
|
||||
* @param tvn
|
||||
* @param m
|
||||
@@ -336,7 +359,7 @@ public class ConfigProcessor extends AbstractProcessor {
|
||||
AnnotationBundle ab = annotationsMap.get(method);
|
||||
String key = ab.key();
|
||||
if (needBlank) {
|
||||
methodBuilder.addStatement("$N.setBlancLinesBefore($N + $S, 1)", layout, prefixMemberName,
|
||||
methodBuilder.addStatement("$N.setBlankLinesBefore($N + $S, 1)", layout, prefixMemberName,
|
||||
key);
|
||||
needBlank = false;
|
||||
}
|
||||
@@ -415,6 +438,14 @@ public class ConfigProcessor extends AbstractProcessor {
|
||||
return methodBuilder.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a method that returns a template object, populated by the default values
|
||||
*
|
||||
* @param tvn
|
||||
* @param m
|
||||
* @param annotationsMap
|
||||
* @return
|
||||
*/
|
||||
private MethodSpec buildGetTemplate(TypeVariableName tvn, Method m,
|
||||
Map<ExecutableElement, AnnotationBundle> annotationsMap) {
|
||||
|
||||
@@ -500,6 +531,15 @@ public class ConfigProcessor extends AbstractProcessor {
|
||||
return methodBuilder.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a method to create a configuration from the object
|
||||
*
|
||||
* @param tvn
|
||||
* @param m
|
||||
* @param annotationsMap
|
||||
* @param prefix
|
||||
* @return
|
||||
*/
|
||||
private MethodSpec buildFromConfig(TypeVariableName tvn, Method m,
|
||||
Map<ExecutableElement, AnnotationBundle> annotationsMap, String prefix) {
|
||||
|
||||
@@ -592,4 +632,107 @@ public class ConfigProcessor extends AbstractProcessor {
|
||||
return methodBuilder.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a method for each member that allows it to be replaced.
|
||||
*
|
||||
* @param tvn
|
||||
* @param annotationsMap
|
||||
* @param prefixMemberName
|
||||
* @return
|
||||
*/
|
||||
private List<MethodSpec> buildWithMethods(TypeVariableName tvn,
|
||||
Map<ExecutableElement, AnnotationBundle> annotationsMap, String prefixMemberName) {
|
||||
|
||||
List<MethodSpec> withMethods = new ArrayList<>();
|
||||
|
||||
ParameterSpec ps = ParameterSpec.builder(tvn, "t").build();
|
||||
|
||||
for (ExecutableElement method : annotationsMap.keySet()) {
|
||||
String methodName = method.getSimpleName().toString();
|
||||
String camelCase = String.format("with%s%s", methodName.substring(0, 1).toUpperCase(),
|
||||
methodName.substring(1));
|
||||
TypeName propertiesConfigurationClass =
|
||||
TypeName.get(org.apache.commons.configuration2.PropertiesConfiguration.class);
|
||||
|
||||
// method with object passed in as an argument
|
||||
MethodSpec.Builder builder = MethodSpec.methodBuilder(camelCase).addModifiers(Modifier.PUBLIC)
|
||||
.returns(propertiesConfigurationClass);
|
||||
builder.addJavadoc("Replace the value of " + methodName);
|
||||
builder.addParameter(ps);
|
||||
builder.addParameter(
|
||||
ParameterSpec.builder(TypeName.get(method.getReturnType()), "replaceValue").build());
|
||||
builder.addStatement("$T config = toConfig($N)", propertiesConfigurationClass, ps);
|
||||
builder.addStatement(String.format("return %s(config, replaceValue)", camelCase));
|
||||
withMethods.add(builder.build());
|
||||
|
||||
// method with PropertiesConfiguration passed in as an argument
|
||||
builder = MethodSpec.methodBuilder(camelCase).addModifiers(Modifier.PUBLIC)
|
||||
.returns(propertiesConfigurationClass);
|
||||
builder.addJavadoc("Replace the value of " + methodName);
|
||||
builder.addParameter(ParameterSpec.builder(propertiesConfigurationClass, "config").build());
|
||||
builder.addParameter(
|
||||
ParameterSpec.builder(TypeName.get(method.getReturnType()), "replaceValue").build());
|
||||
|
||||
AnnotationBundle ab = annotationsMap.get(method);
|
||||
String key = ab.key();
|
||||
|
||||
TypeMirror parser = null;
|
||||
String parserName = null;
|
||||
if (ab.parserClass().isPresent()) {
|
||||
parser = ab.parserClass().get();
|
||||
parserName = method.getSimpleName() + "Parser";
|
||||
builder.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";
|
||||
builder.addStatement("$T " + listName + " = new $T()", listType, arrayListType);
|
||||
builder.beginControlFlow("for (var element : replaceValue)");
|
||||
if (ab.parserClass().isPresent()) {
|
||||
builder.addStatement("$L.add($L.toString(element))", listName, parserName);
|
||||
} else {
|
||||
TypeMirror typeArg = ab.typeArgs().get(0);
|
||||
if (ConfigProcessorUtils.isByte(typeArg, processingEnv))
|
||||
builder.addStatement("$L.add($T.toString(element))", listName, java.lang.Byte.class);
|
||||
if (ConfigProcessorUtils.isBoolean(typeArg, processingEnv))
|
||||
builder.addStatement("$L.add($T.toString(element))", listName, java.lang.Boolean.class);
|
||||
if (ConfigProcessorUtils.isDouble(typeArg, processingEnv))
|
||||
builder.addStatement("$L.add($T.toString(element))", listName, java.lang.Double.class);
|
||||
if (ConfigProcessorUtils.isFloat(typeArg, processingEnv))
|
||||
builder.addStatement("$L.add($T.toString(element))", listName, java.lang.Float.class);
|
||||
if (ConfigProcessorUtils.isInteger(typeArg, processingEnv))
|
||||
builder.addStatement("$L.add($T.toString(element))", listName, java.lang.Integer.class);
|
||||
if (ConfigProcessorUtils.isLong(typeArg, processingEnv))
|
||||
builder.addStatement("$L.add($T.toString(element))", listName, java.lang.Long.class);
|
||||
if (ConfigProcessorUtils.isShort(typeArg, processingEnv))
|
||||
builder.addStatement("$L.add($T.toString(element))", listName, java.lang.Short.class);
|
||||
if (ConfigProcessorUtils.isString(typeArg, processingEnv))
|
||||
builder.addStatement("$L.add(element)", listName);
|
||||
}
|
||||
builder.endControlFlow();
|
||||
builder.addStatement("config.setProperty($N + $S, $L)", prefixMemberName, key, listName);
|
||||
} else {
|
||||
if (ab.parserClass().isPresent()) {
|
||||
// store the serialized string as the property
|
||||
builder.addStatement("config.setProperty($N + $S, $L.toString(replaceValue))",
|
||||
prefixMemberName, key, parserName);
|
||||
} else {
|
||||
builder.addStatement("config.setProperty($N + $S, replaceValue)", prefixMemberName, key);
|
||||
}
|
||||
}
|
||||
|
||||
builder.addStatement("return config");
|
||||
|
||||
withMethods.add(builder.build());
|
||||
}
|
||||
|
||||
return withMethods;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user