Merge branch '14-throw-runtime-exception-if-key-not-found' into 'main'

Resolve "throw runtime exception if key not found"

Closes #14

See merge request nairah1/jackfruit!14
This commit is contained in:
Hari Nair
2023-03-29 18:02:25 +00:00
19 changed files with 302 additions and 161 deletions

1
.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
.idea

View File

@@ -25,23 +25,11 @@
<artifactId>commons-beanutils</artifactId>
<version>1.9.4</version>
</dependency>
<dependency>
<groupId>edu.jhuapl.ses.saa</groupId>
<artifactId>crucible-all</artifactId>
<version>1.0.0-b74-7d477359</version>
<type>pom</type>
</dependency>
<dependency>
<groupId>edu.jhuapl.ses.srn</groupId>
<artifactId>jackfruit</artifactId>
<version>${project.parent.version}</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>

View File

@@ -0,0 +1,179 @@
package crucible.crust.logging;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.core.Appender;
import org.apache.logging.log4j.core.LoggerContext;
import org.apache.logging.log4j.core.appender.ConsoleAppender;
import org.apache.logging.log4j.core.appender.FileAppender;
import org.apache.logging.log4j.core.config.Configuration;
import org.apache.logging.log4j.core.config.Configurator;
import org.apache.logging.log4j.core.config.DefaultConfiguration;
import org.apache.logging.log4j.core.config.LoggerConfig;
import org.apache.logging.log4j.core.layout.PatternLayout;
/**
* A simple configuration class.
* <p>
* Default settings:
* <ul>
* <li>Pattern is "%d{yyyy-MM-dd HH:mm:ss.SSS} %-5level [%c{1}:%L] %msg%n%throwable"<br>
* (e.g. 2021-11-09 19:32:37.119 INFO [LoggingTest:25] Level INFO)</li>
* <li>Log level is {@link Level#INFO}</li>
* </ul>
*
* @author nairah1
*
*/
public class Log4j2Configurator {
private PatternLayout layout;
private final Map<String, FileAppender> fileAppenders;
private static Log4j2Configurator instance = null;
/**
*
* @return an instance of this singleton class.
*/
synchronized public static Log4j2Configurator getInstance() {
if (instance == null) {
instance = new Log4j2Configurator();
}
return instance;
}
private Log4j2Configurator() {
final LoggerContext loggerContext = LoggerContext.getContext(false);
final Configuration config = loggerContext.getConfiguration();
layout = PatternLayout.newBuilder().withPattern(DefaultConfiguration.DEFAULT_PATTERN)
.withConfiguration(config).build();
fileAppenders = new HashMap<>();
setPattern("%d{yyyy-MM-dd HH:mm:ss.SSS} %-5level [%c{1}:%L] %msg%n%throwable");
setLevel(Level.INFO);
}
/**
*
* @return a map of logger names to {@link LoggerConfig}
*/
private Map<String, LoggerConfig> getLoggerMap() {
final LoggerContext loggerContext = LoggerContext.getContext(false);
final Configuration config = loggerContext.getConfiguration();
Map<String, LoggerConfig> loggerMap = new HashMap<>(config.getLoggers());
loggerMap.put(LogManager.getRootLogger().getName(),
config.getLoggerConfig(LogManager.getRootLogger().getName()));
return Collections.unmodifiableMap(loggerMap);
}
/**
*
*
* @param filename Append log to named file, or create it if it doesn't exist.
*/
public void addFile(String filename) {
final LoggerContext loggerContext = LoggerContext.getContext(false);
Map<String, LoggerConfig> loggerMap = getLoggerMap();
FileAppender appender = FileAppender.newBuilder().setName(filename).withFileName(filename)
.setLayout(layout).build();
appender.start();
for (String loggerName : loggerMap.keySet()) {
LoggerConfig loggerConfig = loggerMap.get(loggerName);
loggerConfig.addAppender(appender, null, null);
}
loggerContext.updateLoggers();
fileAppenders.put(filename, appender);
}
/**
*
*
* @param filename Stop logging to named file.
*/
public void removeFile(String filename) {
if (fileAppenders.containsKey(filename)) {
final LoggerContext loggerContext = LoggerContext.getContext(false);
Map<String, LoggerConfig> loggerMap = getLoggerMap();
FileAppender appender = fileAppenders.get(filename);
for (String loggerName : loggerMap.keySet()) {
LoggerConfig loggerConfig = loggerMap.get(loggerName);
loggerConfig.removeAppender(appender.getName());
}
loggerContext.updateLoggers();
fileAppenders.remove(filename);
}
}
/**
*
* @param pattern layout pattern for all {@link ConsoleAppender} and {@link FileAppender} objects.
*/
public void setPattern(String pattern) {
final LoggerContext loggerContext = LoggerContext.getContext(false);
final Configuration config = loggerContext.getConfiguration();
layout = PatternLayout.newBuilder().withConfiguration(config).withPattern(pattern).build();
Map<String, LoggerConfig> loggerMap = getLoggerMap();
for (String loggerName : loggerMap.keySet()) {
LoggerConfig loggerConfig = loggerMap.get(loggerName);
Map<String, Appender> appenderMap = loggerConfig.getAppenders();
for (String appenderName : appenderMap.keySet()) {
Appender newAppender = null;
Appender oldAppender = appenderMap.get(appenderName);
// there should be a better way to do this - a toBuilder() method on the appender would be
// really useful
if (oldAppender instanceof ConsoleAppender) {
newAppender = ConsoleAppender.newBuilder().setName(appenderName).setConfiguration(config)
.setLayout(layout).build();
} else if (oldAppender instanceof FileAppender) {
newAppender = FileAppender.newBuilder().setName(appenderName).setConfiguration(config)
.withFileName(((FileAppender) oldAppender).getFileName()).setLayout(layout).build();
}
if (newAppender != null) {
newAppender.start();
loggerConfig.removeAppender(appenderName);
loggerConfig.addAppender(newAppender, null, null);
}
}
}
loggerContext.updateLoggers();
}
/**
* Sets the levels of <code>parentLogger</code> and all 'child' loggers to the given
* <code>level</code>. This is simply a call to
*
* <pre>
* Configurator.setAllLevels(parentLogger, level)
* </pre>
*
* @param parentLogger
* @param level
*/
public void setLevel(String parentLogger, Level level) {
Configurator.setAllLevels(parentLogger, level);
}
/**
* Set all logger levels. This is simply a call to
*
* <pre>
* setLevel(LogManager.getRootLogger().getName(), level)
* </pre>
*
* @param level
*/
public void setLevel(Level level) {
setLevel(LogManager.getRootLogger().getName(), level);
}
}

View File

@@ -2,7 +2,7 @@ package jackfruit.demo;
public class SomeRandomClass {
private String internalString;
private final String internalString;
public String getInternalString() {
return internalString;

View File

@@ -1,9 +1,11 @@
package jackfruit.demo;
import crucible.crust.logging.Log4j2Configurator;
import jackfruit.processor.ConfigProcessor;
import java.io.File;
import java.io.PrintWriter;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import javax.tools.JavaCompiler;
import javax.tools.JavaCompiler.CompilationTask;
@@ -13,8 +15,6 @@ import javax.tools.StandardJavaFileManager;
import javax.tools.StandardLocation;
import javax.tools.ToolProvider;
import org.junit.Test;
import crucible.crust.logging.Log4j2Configurator;
import jackfruit.processor.ConfigProcessor;
/**
* From <a href=
@@ -48,7 +48,7 @@ public class TestProcessor {
CompilationTask task =
compiler.getTask(new PrintWriter(System.out), null, null, null, null, files);
task.setProcessors(Arrays.asList(new ConfigProcessor()));
task.setProcessors(List.of(new ConfigProcessor()));
task.call();
}
@@ -58,7 +58,7 @@ public class TestProcessor {
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
StandardJavaFileManager files = compiler.getStandardFileManager(null, null, null);
files.setLocation(StandardLocation.SOURCE_PATH, Arrays.asList(new File(p_path)));
files.setLocation(StandardLocation.SOURCE_PATH, List.of(new File(p_path)));
Set<Kind> fileKinds = Collections.singleton(Kind.SOURCE);
return files.list(StandardLocation.SOURCE_PATH, "", fileKinds, true);

View File

@@ -30,17 +30,11 @@
<maven-compiler-plugin.version>
3.10.1
</maven-compiler-plugin.version>
<log4j-version>2.19.0</log4j-version>
<log4j-version>2.20.0</log4j-version>
<immutables.version>2.9.2</immutables.version>
</properties>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.google.auto.service</groupId>
<artifactId>auto-service</artifactId>

View File

@@ -2,23 +2,29 @@
# This script is run from maven. See the exec-maven-plugin block in the pom.xml file.
cd $(dirname $0)
package=jackfruit
srcFile="../java/jackfruit/JackfruitVersion.java"
rev=$(git rev-parse --verify --short=8 HEAD)
if [ $? -gt 0 ]; then
rev="UNKNOWN"
fi
branch=$(git symbolic-ref --short HEAD)
if [ $? -gt 0 ]; then
branch="UNKNOWN"
fi
cd $(dirname "$0")
date=$(date -u +"%y.%m.%d")
package=jackfruit
srcFile="../java/jackfruit/JackfruitVersion.java"
mkdir -p $(dirname $srcFile)
rev=$(git rev-parse --verify --short HEAD)
if [ $? -gt 0 ]; then
lastCommit=$(date -u +"%y.%m.%d")
rev="UNVERSIONED"
else
lastCommit=$(git log -1 --format=%cd --date=format:%y.%m.%d)
rev=$(git rev-parse --verify --short HEAD)
if [[ $(git diff --stat) != '' ]]; then
if [[ $(git status -s | grep -v pom.xml | grep -v pom.bak | grep -v .m2 | grep -v $srcFile) != '' ]]; then
rev=${rev}M
fi
fi
fi
mkdir -p $(dirname "$srcFile")
touch $srcFile
@@ -27,10 +33,11 @@ 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 dateString = new String("$date");
public final static String branch = new String("$branch");
public final static String lastCommit = "$lastCommit";
// an M at the end of gitRevision means this was built from a "dirty" git repository
public final static String rev = "$rev";
public final static String packageName = "$package";
public final static String dateString = "$date";
}
EOF

View File

@@ -2,9 +2,10 @@
package jackfruit;
public class JackfruitVersion {
public final static String rev = new String("9ad69b62");
public final static String packageName = new String("jackfruit");
public final static String dateString = new String("22.11.27");
public final static String branch = new String("UNKNOWN");
public final static String lastCommit = "23.03.29";
// an M at the end of gitRevision means this was built from a "dirty" git repository
public final static String rev = "b200487M";
public final static String packageName = "jackfruit";
public final static String dateString = "23.03.29";
}

View File

@@ -15,5 +15,5 @@ import java.lang.annotation.Target;
@Retention(RetentionPolicy.SOURCE)
@Target(ElementType.METHOD)
public @interface Comment {
public String value() default "";
String value() default "";
}

View File

@@ -19,5 +19,5 @@ import java.lang.annotation.Target;
@Retention(RetentionPolicy.SOURCE)
@Target(ElementType.METHOD)
public @interface DefaultValue {
public String value() default "";
String value() default "";
}

View File

@@ -21,5 +21,5 @@ import java.lang.annotation.Target;
@Retention(RetentionPolicy.SOURCE)
@Target(ElementType.TYPE)
public @interface Jackfruit {
public String prefix() default "";
String prefix() default "";
}

View File

@@ -15,5 +15,5 @@ import java.lang.annotation.Target;
@Retention(RetentionPolicy.SOURCE)
@Target(ElementType.METHOD)
public @interface Key {
public String value() default "";
String value() default "";
}

View File

@@ -8,7 +8,7 @@ package jackfruit.annotations;
* @param <T>
*/
public interface Parser<T> {
public T fromString(String s);
T fromString(String s);
public String toString(T t);
String toString(T t);
}

View File

@@ -15,5 +15,5 @@ import java.lang.annotation.Target;
@Retention(RetentionPolicy.SOURCE)
@Target(ElementType.METHOD)
public @interface ParserClass {
public Class<?> value();
Class<?> value();
}

View File

@@ -1,64 +1,51 @@
package jackfruit.processor;
import jackfruit.annotations.Parser;
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
*
* @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&lt;String&gt;)
* List&lt;String&gt;)
*/
public abstract TypeMirror erasure();
/**
*
* @return the parameterized types, if any of this method (e.g. return String if the annotated
* method returns List&lt;String&gt;)
* method returns List&lt;String&gt;)
*/
public abstract List<TypeMirror> typeArgs();
/**
* Comment for this configuration parameter. This can be blank.
*
* @return
* @return Comment for this configuration parameter. This can be blank.
*/
public abstract String comment();
/**
* Default value for this configuration parameter. This is required.
*
* @return
* @return Default value for this configuration parameter. This is required.
*/
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
* @return Key used in the configuration file. If omitted, default value is the name of the
* configuration parameter (the method name).
*/
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
* @return 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}.
*/
public abstract Optional<TypeMirror> parserClass();
}

View File

@@ -7,47 +7,38 @@ 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
*
* @author nairah1
* @param <T>
*/
public interface ConfigFactory<T> {
/**
* This returns an object of type T with default values.
*
* @return
* @return This returns an object of type T with default values.
*/
T getTemplate();
/**
* This creates an object of type T from the supplied Apache Commons {@link Configuration}.
*
* @param config
* @return
* @param config configuration to turn into an object of type T
* @return an object of type T from the supplied Apache Commons {@link Configuration}.
*/
T fromConfig(Configuration config);
/**
* This creates an Apache Commons {@link PropertiesConfiguration} from the supplied object T.
*
* @param t
* @param t object to convert to a configuration
* @param layout used for formatting the returned PropertiesConfiguration
* @return
* @return an Apache Commons {@link PropertiesConfiguration} from the supplied object T.
*/
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
* This is simply a call to {@link #toConfig(Object, PropertiesConfigurationLayout)} with a new
* PropertiesConfigurationLayout().
*
* @param t
* @return
*
* @param t object to convert to a configuration
* @return an Apache Commons {@link PropertiesConfiguration} from the supplied object T.
*/
default PropertiesConfiguration toConfig(T t) {
return toConfig(t, new PropertiesConfigurationLayout());
}
}

View File

@@ -95,10 +95,9 @@ public class ConfigProcessor extends AbstractProcessor {
for (Element element : annotatedElements) {
try {
if (element instanceof TypeElement) {
TypeElement annotatedType = (TypeElement) element;
if (element instanceof TypeElement annotatedType) {
Jackfruit configParams = (Jackfruit) annotatedType.getAnnotation(Jackfruit.class);
Jackfruit configParams = annotatedType.getAnnotation(Jackfruit.class);
String prefix = configParams.prefix().strip();
if (prefix.length() > 0 && !prefix.endsWith("."))
prefix += ".";
@@ -161,9 +160,9 @@ public class ConfigProcessor extends AbstractProcessor {
Map<Name, AnnotationBundle> defaultAnnotationsMap = new LinkedHashMap<>();
for (DeclaredType thisType : classHierarchy) {
for (Element e : thisType.asElement().getEnclosedElements()) {
if (e.getKind() == ElementKind.METHOD && e.getAnnotation(DefaultValue.class) != null
&& e instanceof ExecutableElement) {
ExecutableElement ex = (ExecutableElement) e;
if (e.getKind() == ElementKind.METHOD
&& e.getAnnotation(DefaultValue.class) != null
&& e instanceof ExecutableElement ex) {
enclosedMethods.put(ex.getSimpleName(), ex);
AnnotationBundle defaultValues = defaultAnnotationsMap.get(ex.getSimpleName());
defaultAnnotationsMap.put(ex.getSimpleName(),
@@ -301,8 +300,7 @@ public class ConfigProcessor extends AbstractProcessor {
builder.comment(((Comment) annotation).value());
} else if (annotation instanceof DefaultValue) {
builder.defaultValue(((DefaultValue) annotation).value());
} else if (annotation instanceof ParserClass) {
ParserClass pc = (ParserClass) annotation;
} else if (annotation instanceof ParserClass pc) {
// this works, but there has to be a better way?
TypeMirror tm;
@@ -334,7 +332,7 @@ public class ConfigProcessor extends AbstractProcessor {
* @param tvn
* @param m
* @param annotationsMap
* @param prefix
* @param prefixMemberName
* @return
*/
private MethodSpec buildToConfig(TypeVariableName tvn, Method m,
@@ -554,6 +552,12 @@ public class ConfigProcessor extends AbstractProcessor {
.addModifiers(Modifier.PUBLIC).addAnnotation(Override.class)
.returns(TypeName.get(method.getReturnType())).addJavadoc(bundle.comment());
builder.addStatement("String key = $N + $S", prefix, bundle.key());
builder
.beginControlFlow("if (!config.containsKey(key))")
.addStatement("throw new $T($S + key)", RuntimeException.class, "No such key")
.endControlFlow();
TypeMirror parser = null;
String parserName = null;
if (bundle.parserClass().isPresent()) {
@@ -570,8 +574,7 @@ public class ConfigProcessor extends AbstractProcessor {
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 [] parts = config.getStringArray($N + $S)", prefix,
bundle.key());
builder.addStatement("String [] parts = config.getStringArray(key)");
builder.beginControlFlow("for (String part : parts)");
builder.beginControlFlow("if (part.trim().length() > 0)");
if (bundle.parserClass().isPresent()) {
@@ -600,25 +603,24 @@ public class ConfigProcessor extends AbstractProcessor {
builder.addStatement("return $L", listName);
} else {
if (bundle.parserClass().isPresent()) {
builder.addStatement("return $L.fromString(config.getString($N + $S))", parserName,
prefix, bundle.key());
builder.addStatement("return $L.fromString(config.getString(key))", parserName);
} else {
if (ConfigProcessorUtils.isBoolean(bundle.erasure(), processingEnv)) {
builder.addStatement("return config.getBoolean($N + $S)", prefix, bundle.key());
builder.addStatement("return config.getBoolean(key)");
} else if (ConfigProcessorUtils.isByte(bundle.erasure(), processingEnv)) {
builder.addStatement("return config.getByte($N + $S)", prefix, bundle.key());
builder.addStatement("return config.getByte(key)");
} else if (ConfigProcessorUtils.isDouble(bundle.erasure(), processingEnv)) {
builder.addStatement("return config.getDouble($N + $S)", prefix, bundle.key());
builder.addStatement("return config.getDouble(key)");
} else if (ConfigProcessorUtils.isFloat(bundle.erasure(), processingEnv)) {
builder.addStatement("return config.getFloat($N + $S)", prefix, bundle.key());
builder.addStatement("return config.getFloat(key)");
} else if (ConfigProcessorUtils.isInteger(bundle.erasure(), processingEnv)) {
builder.addStatement("return config.getInt($N + $S)", prefix, bundle.key());
builder.addStatement("return config.getInt(key)");
} else if (ConfigProcessorUtils.isLong(bundle.erasure(), processingEnv)) {
builder.addStatement("return config.getLong($N + $S)", prefix, bundle.key());
builder.addStatement("return config.getLong(key)");
} else if (ConfigProcessorUtils.isShort(bundle.erasure(), processingEnv)) {
builder.addStatement("return config.getShort($N + $S)", prefix, bundle.key());
builder.addStatement("return config.getShort(key)");
} else if (ConfigProcessorUtils.isString(bundle.erasure(), processingEnv)) {
builder.addStatement("return config.getString($N + $S)", prefix, bundle.key());
builder.addStatement("return config.getString(key)");
} else {
processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR,
"Can't handle return type " + m.getReturnType().getCanonicalName());

View File

@@ -10,123 +10,114 @@ 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) {
public 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 typeMirror either {@link AnnotationBundle#erasure()} for the return value, or an element of {@link
* AnnotationBundle#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) {
public 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 typeMirror either {@link AnnotationBundle#erasure()} for the return value, or an element of {@link
* AnnotationBundle#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) {
public 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 typeMirror either {@link AnnotationBundle#erasure()} for the return value, or an element of {@link
* AnnotationBundle#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) {
public 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 typeMirror either {@link AnnotationBundle#erasure()} for the return value, or an element of {@link
* AnnotationBundle#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) {
public 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 typeMirror either {@link AnnotationBundle#erasure()} for the return value, or an element of {@link
* AnnotationBundle#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) {
public 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 typeMirror either {@link AnnotationBundle#erasure()} for the return value, or an element of {@link
* AnnotationBundle#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) {
public 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 typeMirror either {@link AnnotationBundle#erasure()} for the return value, or an element of {@link
* AnnotationBundle#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) {
public 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 typeMirror either {@link AnnotationBundle#erasure()} for the return value, or an element of {@link
* AnnotationBundle#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) {
public 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) {
private 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()));
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()));
return types.isSubtype(
typeMirror, types.erasure(elements.getTypeElement(compareTo.getCanonicalName()).asType()));
}
}

View File

@@ -26,7 +26,7 @@
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<version>4.13.2</version>
<scope>test</scope>
</dependency>
</dependencies>