This is an automated email from the ASF dual-hosted git repository.
paulk pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/groovy.git
The following commit(s) were added to refs/heads/master by this push:
new 38d6a71 GROOVY-7233: Configurable Access Modifier for Log AST
Transformations (closes #843)
38d6a71 is described below
commit 38d6a7198b5714cf3df5e5778a10a76d5301efc1
Author: Joe Wolf <[email protected]>
AuthorDate: Tue Dec 30 00:28:34 2014 -0500
GROOVY-7233: Configurable Access Modifier for Log AST Transformations
(closes #843)
All of the logging AST transformations now support @VisibilityOptions.
This allows the log field to be public, private (the default), protected,
or package-private. There is a new LoggingStrategyV2 which logging
strategies which want to support visibility should support.
---
src/main/groovy/groovy/util/logging/Commons.java | 15 +++-
src/main/groovy/groovy/util/logging/Log.java | 16 +++-
src/main/groovy/groovy/util/logging/Log4j.java | 16 +++-
src/main/groovy/groovy/util/logging/Log4j2.java | 16 +++-
src/main/groovy/groovy/util/logging/Slf4j.java | 16 +++-
.../groovy/transform/LogASTTransformation.java | 71 ++++++++++++++++-
src/test/groovy/util/logging/CommonsTest.groovy | 80 ++++++++++++++++++-
src/test/groovy/util/logging/Log4j2Test.groovy | 89 +++++++++++++++++++++-
src/test/groovy/util/logging/Log4jTest.groovy | 70 +++++++++++++++++
src/test/groovy/util/logging/LogTest.groovy | 73 +++++++++++++++++-
src/test/groovy/util/logging/Slf4jTest.groovy | 70 +++++++++++++++++
11 files changed, 504 insertions(+), 28 deletions(-)
diff --git a/src/main/groovy/groovy/util/logging/Commons.java
b/src/main/groovy/groovy/util/logging/Commons.java
index d4e5ad6..6b145b4 100644
--- a/src/main/groovy/groovy/util/logging/Commons.java
+++ b/src/main/groovy/groovy/util/logging/Commons.java
@@ -19,6 +19,7 @@
package groovy.util.logging;
import groovy.lang.GroovyClassLoader;
+import groovy.transform.Undefined;
import org.codehaus.groovy.ast.ClassNode;
import org.codehaus.groovy.ast.FieldNode;
import org.codehaus.groovy.ast.expr.ArgumentListExpression;
@@ -30,7 +31,6 @@ import org.codehaus.groovy.ast.expr.MethodCallExpression;
import org.codehaus.groovy.ast.expr.TernaryExpression;
import org.codehaus.groovy.transform.GroovyASTTransformationClass;
import org.codehaus.groovy.transform.LogASTTransformation;
-import org.objectweb.asm.Opcodes;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
@@ -65,9 +65,15 @@ import java.util.Locale;
public @interface Commons {
String value() default "log";
String category() default LogASTTransformation.DEFAULT_CATEGORY_NAME;
+
+ /**
+ * If specified, must match the "id" attribute in a VisibilityOptions
annotation to enable a custom visibility.
+ */
+ String visibilityId() default Undefined.STRING;
+
Class<? extends LogASTTransformation.LoggingStrategy> loggingStrategy()
default CommonsLoggingStrategy.class;
- public static class CommonsLoggingStrategy extends
LogASTTransformation.AbstractLoggingStrategy {
+ public static class CommonsLoggingStrategy extends
LogASTTransformation.AbstractLoggingStrategyV2 {
private static final String LOGGER_NAME =
"org.apache.commons.logging.Log";
private static final String LOGGERFACTORY_NAME =
"org.apache.commons.logging.LogFactory";
@@ -76,9 +82,10 @@ public @interface Commons {
super(loader);
}
- public FieldNode addLoggerFieldToClass(ClassNode classNode, String
logFieldName, String categoryName) {
+ @Override
+ public FieldNode addLoggerFieldToClass(ClassNode classNode, String
logFieldName, String categoryName, int fieldModifiers) {
return classNode.addField(logFieldName,
- Opcodes.ACC_FINAL | Opcodes.ACC_TRANSIENT |
Opcodes.ACC_STATIC | Opcodes.ACC_PRIVATE,
+ fieldModifiers,
classNode(LOGGER_NAME),
new MethodCallExpression(
new ClassExpression(classNode(LOGGERFACTORY_NAME)),
diff --git a/src/main/groovy/groovy/util/logging/Log.java
b/src/main/groovy/groovy/util/logging/Log.java
index 1a4e554..f99d278 100644
--- a/src/main/groovy/groovy/util/logging/Log.java
+++ b/src/main/groovy/groovy/util/logging/Log.java
@@ -19,6 +19,7 @@
package groovy.util.logging;
import groovy.lang.GroovyClassLoader;
+import groovy.transform.Undefined;
import org.codehaus.groovy.ast.ClassHelper;
import org.codehaus.groovy.ast.ClassNode;
import org.codehaus.groovy.ast.FieldNode;
@@ -33,7 +34,6 @@ import org.codehaus.groovy.ast.expr.TernaryExpression;
import org.codehaus.groovy.transform.GroovyASTTransformationClass;
import org.codehaus.groovy.transform.LogASTTransformation;
import org.codehaus.groovy.transform.LogASTTransformation.LoggingStrategy;
-import org.objectweb.asm.Opcodes;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
@@ -70,12 +70,19 @@ import java.util.Locale;
public @interface Log {
String value() default "log";
String category() default LogASTTransformation.DEFAULT_CATEGORY_NAME;
+
+ /**
+ * If specified, must match the "id" attribute in a VisibilityOptions
annotation to enable a custom visibility.
+ * @since 3.0.0
+ */
+ String visibilityId() default Undefined.STRING;
+
Class<? extends LoggingStrategy> loggingStrategy() default
JavaUtilLoggingStrategy.class;
/**
* This class contains the logic of how to weave a Java Util Logging
logger into the host class.
*/
- public static class JavaUtilLoggingStrategy extends
LogASTTransformation.AbstractLoggingStrategy {
+ public static class JavaUtilLoggingStrategy extends
LogASTTransformation.AbstractLoggingStrategyV2 {
private static final ClassNode LOGGER_CLASSNODE =
ClassHelper.make(java.util.logging.Logger.class);
private static final ClassNode LEVEL_CLASSNODE =
ClassHelper.make(java.util.logging.Level.class);
@@ -84,9 +91,10 @@ public @interface Log {
super(loader);
}
- public FieldNode addLoggerFieldToClass(ClassNode classNode, String
logFieldName, String categoryName) {
+ @Override
+ public FieldNode addLoggerFieldToClass(ClassNode classNode, String
logFieldName, String categoryName, int fieldModifiers) {
return classNode.addField(logFieldName,
- Opcodes.ACC_FINAL | Opcodes.ACC_TRANSIENT |
Opcodes.ACC_STATIC | Opcodes.ACC_PRIVATE,
+ fieldModifiers,
LOGGER_CLASSNODE,
new MethodCallExpression(
new ClassExpression(LOGGER_CLASSNODE),
diff --git a/src/main/groovy/groovy/util/logging/Log4j.java
b/src/main/groovy/groovy/util/logging/Log4j.java
index 28633b5..1db7bf9 100644
--- a/src/main/groovy/groovy/util/logging/Log4j.java
+++ b/src/main/groovy/groovy/util/logging/Log4j.java
@@ -19,6 +19,7 @@
package groovy.util.logging;
import groovy.lang.GroovyClassLoader;
+import groovy.transform.Undefined;
import org.codehaus.groovy.ast.ClassNode;
import org.codehaus.groovy.ast.FieldNode;
import org.codehaus.groovy.ast.expr.ArgumentListExpression;
@@ -31,7 +32,6 @@ import org.codehaus.groovy.ast.expr.MethodCallExpression;
import org.codehaus.groovy.ast.expr.TernaryExpression;
import org.codehaus.groovy.transform.GroovyASTTransformationClass;
import org.codehaus.groovy.transform.LogASTTransformation;
-import org.objectweb.asm.Opcodes;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
@@ -66,9 +66,16 @@ import java.util.Locale;
public @interface Log4j {
String value() default "log";
String category() default LogASTTransformation.DEFAULT_CATEGORY_NAME;
+
+ /**
+ * If specified, must match the "id" attribute in a VisibilityOptions
annotation to enable a custom visibility.
+ * @since 3.0.0
+ */
+ String visibilityId() default Undefined.STRING;
+
Class<? extends LogASTTransformation.LoggingStrategy> loggingStrategy()
default Log4jLoggingStrategy.class;
- public static class Log4jLoggingStrategy extends
LogASTTransformation.AbstractLoggingStrategy {
+ public static class Log4jLoggingStrategy extends
LogASTTransformation.AbstractLoggingStrategyV2 {
private static final String LOGGER_NAME = "org.apache.log4j.Logger";
private static final String PRIORITY_NAME =
"org.apache.log4j.Priority";
@@ -76,9 +83,10 @@ public @interface Log4j {
super(loader);
}
- public FieldNode addLoggerFieldToClass(ClassNode classNode, String
logFieldName, String categoryName) {
+ @Override
+ public FieldNode addLoggerFieldToClass(ClassNode classNode, String
logFieldName, String categoryName, int fieldModifiers) {
return classNode.addField(logFieldName,
- Opcodes.ACC_FINAL | Opcodes.ACC_TRANSIENT |
Opcodes.ACC_STATIC | Opcodes.ACC_PRIVATE,
+ fieldModifiers,
classNode(LOGGER_NAME),
new MethodCallExpression(
new ClassExpression(classNode(LOGGER_NAME)),
diff --git a/src/main/groovy/groovy/util/logging/Log4j2.java
b/src/main/groovy/groovy/util/logging/Log4j2.java
index a53874c..d9a8a8a 100644
--- a/src/main/groovy/groovy/util/logging/Log4j2.java
+++ b/src/main/groovy/groovy/util/logging/Log4j2.java
@@ -19,6 +19,7 @@
package groovy.util.logging;
import groovy.lang.GroovyClassLoader;
+import groovy.transform.Undefined;
import org.codehaus.groovy.ast.ClassNode;
import org.codehaus.groovy.ast.FieldNode;
import org.codehaus.groovy.ast.expr.ArgumentListExpression;
@@ -30,7 +31,6 @@ import org.codehaus.groovy.ast.expr.MethodCallExpression;
import org.codehaus.groovy.ast.expr.TernaryExpression;
import org.codehaus.groovy.transform.GroovyASTTransformationClass;
import org.codehaus.groovy.transform.LogASTTransformation;
-import org.objectweb.asm.Opcodes;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
@@ -65,9 +65,16 @@ import java.util.Locale;
public @interface Log4j2 {
String value() default "log";
String category() default LogASTTransformation.DEFAULT_CATEGORY_NAME;
+
+ /**
+ * If specified, must match the "id" attribute in a VisibilityOptions
annotation to enable a custom visibility.
+ * @since 3.0.0
+ */
+ String visibilityId() default Undefined.STRING;
+
Class<? extends LogASTTransformation.LoggingStrategy> loggingStrategy()
default Log4j2LoggingStrategy.class;
- public static class Log4j2LoggingStrategy extends
LogASTTransformation.AbstractLoggingStrategy {
+ public static class Log4j2LoggingStrategy extends
LogASTTransformation.AbstractLoggingStrategyV2 {
private static final String LOGGER_NAME =
"org.apache.logging.log4j.core.Logger";
private static final String LOG_MANAGER_NAME =
"org.apache.logging.log4j.LogManager";
@@ -75,9 +82,10 @@ public @interface Log4j2 {
super(loader);
}
- public FieldNode addLoggerFieldToClass(ClassNode classNode, String
logFieldName, String categoryName) {
+ @Override
+ public FieldNode addLoggerFieldToClass(ClassNode classNode, String
logFieldName, String categoryName, int fieldModifiers) {
return classNode.addField(logFieldName,
- Opcodes.ACC_FINAL | Opcodes.ACC_TRANSIENT |
Opcodes.ACC_STATIC | Opcodes.ACC_PRIVATE,
+ fieldModifiers,
classNode(LOGGER_NAME),
new MethodCallExpression(
new ClassExpression(classNode(LOG_MANAGER_NAME)),
diff --git a/src/main/groovy/groovy/util/logging/Slf4j.java
b/src/main/groovy/groovy/util/logging/Slf4j.java
index 7561cf7..4f7da07 100644
--- a/src/main/groovy/groovy/util/logging/Slf4j.java
+++ b/src/main/groovy/groovy/util/logging/Slf4j.java
@@ -19,6 +19,7 @@
package groovy.util.logging;
import groovy.lang.GroovyClassLoader;
+import groovy.transform.Undefined;
import org.codehaus.groovy.ast.ClassNode;
import org.codehaus.groovy.ast.FieldNode;
import org.codehaus.groovy.ast.expr.ArgumentListExpression;
@@ -30,7 +31,6 @@ import org.codehaus.groovy.ast.expr.MethodCallExpression;
import org.codehaus.groovy.ast.expr.TernaryExpression;
import org.codehaus.groovy.transform.GroovyASTTransformationClass;
import org.codehaus.groovy.transform.LogASTTransformation;
-import org.objectweb.asm.Opcodes;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
@@ -65,9 +65,16 @@ import java.util.Locale;
public @interface Slf4j {
String value() default "log";
String category() default LogASTTransformation.DEFAULT_CATEGORY_NAME;
+
+ /**
+ * If specified, must match the "id" attribute in a VisibilityOptions
annotation to enable a custom visibility.
+ * @since 3.0.0
+ */
+ String visibilityId() default Undefined.STRING;
+
Class<? extends LogASTTransformation.LoggingStrategy> loggingStrategy()
default Slf4jLoggingStrategy.class;
- public static class Slf4jLoggingStrategy extends
LogASTTransformation.AbstractLoggingStrategy {
+ public static class Slf4jLoggingStrategy extends
LogASTTransformation.AbstractLoggingStrategyV2 {
private static final String LOGGER_NAME = "org.slf4j.Logger";
private static final String FACTORY_NAME = "org.slf4j.LoggerFactory";
@@ -75,9 +82,10 @@ public @interface Slf4j {
super(loader);
}
- public FieldNode addLoggerFieldToClass(ClassNode classNode, String
logFieldName, String categoryName) {
+ @Override
+ public FieldNode addLoggerFieldToClass(ClassNode classNode, String
logFieldName, String categoryName, int fieldModifiers) {
return classNode.addField(logFieldName,
- Opcodes.ACC_FINAL | Opcodes.ACC_TRANSIENT |
Opcodes.ACC_STATIC | Opcodes.ACC_PRIVATE,
+ fieldModifiers,
classNode(LOGGER_NAME),
new MethodCallExpression(
new ClassExpression(classNode(FACTORY_NAME)),
diff --git
a/src/main/java/org/codehaus/groovy/transform/LogASTTransformation.java
b/src/main/java/org/codehaus/groovy/transform/LogASTTransformation.java
index 1895062..c2505ff 100644
--- a/src/main/java/org/codehaus/groovy/transform/LogASTTransformation.java
+++ b/src/main/java/org/codehaus/groovy/transform/LogASTTransformation.java
@@ -46,6 +46,10 @@ import org.codehaus.groovy.runtime.DefaultGroovyMethods;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
+import org.objectweb.asm.Opcodes;
+
+import static org.apache.groovy.ast.tools.VisibilityUtils.getVisibility;
+
/**
* This class provides an AST Transformation to add a log field to a class.
*/
@@ -58,6 +62,8 @@ public class LogASTTransformation extends
AbstractASTTransformation implements C
*/
public static final String DEFAULT_CATEGORY_NAME =
"##default-category-name##";
+ public static final String DEFAULT_ACCESS_MODIFIER = "private";
+
private CompilationUnit compilationUnit;
@Override
@@ -74,6 +80,8 @@ public class LogASTTransformation extends
AbstractASTTransformation implements C
final String categoryName = lookupCategoryName(logAnnotation);
+ final int logFieldModifiers = lookupLogFieldModifiers(targetClass,
logAnnotation);
+
if (!(targetClass instanceof ClassNode))
throw new GroovyBugError("Class annotation " +
logAnnotation.getClassNode().getName() + " annotated no Class, this must not
happen.");
@@ -107,7 +115,13 @@ public class LogASTTransformation extends
AbstractASTTransformation implements C
} else if (logField != null &&
!Modifier.isPrivate(logField.getModifiers())) {
addError("Class annotated with Log annotation cannot have
log field declared because the field exists in the parent class: " +
logField.getOwner().getName(), logField);
} else {
- logNode = loggingStrategy.addLoggerFieldToClass(node,
logFieldName, categoryName);
+ if (loggingStrategy instanceof LoggingStrategyV2) {
+ LoggingStrategyV2 loggingStrategyV2 =
(LoggingStrategyV2) loggingStrategy;
+ logNode =
loggingStrategyV2.addLoggerFieldToClass(node, logFieldName, categoryName,
logFieldModifiers);
+ } else {
+ // support the old style but they won't be as
configurable
+ logNode = loggingStrategy.addLoggerFieldToClass(node,
logFieldName, categoryName);
+ }
}
super.visitClass(node);
}
@@ -189,6 +203,11 @@ public class LogASTTransformation extends
AbstractASTTransformation implements C
return DEFAULT_CATEGORY_NAME;
}
+ private int lookupLogFieldModifiers(AnnotatedNode targetClass,
AnnotationNode logAnnotation) {
+ int modifiers = getVisibility(logAnnotation, targetClass,
ClassNode.class, Opcodes.ACC_PRIVATE);
+ return Opcodes.ACC_FINAL | Opcodes.ACC_TRANSIENT | Opcodes.ACC_STATIC
| modifiers;
+ }
+
private static LoggingStrategy createLoggingStrategy(AnnotationNode
logAnnotation, GroovyClassLoader loader) {
String annotationName = logAnnotation.getClassNode().getName();
@@ -214,10 +233,23 @@ public class LogASTTransformation extends
AbstractASTTransformation implements C
throw new RuntimeException("Could not find default value of method
named loggingStrategy on class named " + annotationName);
}
- if (!LoggingStrategy.class.isAssignableFrom((Class) defaultValue)) {
+ if (!LoggingStrategy.class.isAssignableFrom((Class) defaultValue)
+ && !LoggingStrategyV2.class.isAssignableFrom((Class)
defaultValue)) {
throw new RuntimeException("Default loggingStrategy value on class
named " + annotationName + " is not a LoggingStrategy");
}
+ // try V2 configurable logging strategy
+ try {
+ Class<? extends LoggingStrategyV2> strategyClass = (Class<?
extends LoggingStrategyV2>) defaultValue;
+ if (AbstractLoggingStrategy.class.isAssignableFrom(strategyClass))
{
+ return DefaultGroovyMethods.newInstance(strategyClass, new
Object[]{loader});
+ } else {
+ return strategyClass.newInstance();
+ }
+ } catch (Exception e) {
+ }
+
+ // try legacy logging strategy
try {
Class<? extends LoggingStrategy> strategyClass = (Class<? extends
LoggingStrategy>) defaultValue;
if (AbstractLoggingStrategy.class.isAssignableFrom(strategyClass))
{
@@ -228,6 +260,7 @@ public class LogASTTransformation extends
AbstractASTTransformation implements C
} catch (Exception e) {
return null;
}
+
}
@@ -255,6 +288,40 @@ public class LogASTTransformation extends
AbstractASTTransformation implements C
Expression wrapLoggingMethodCall(Expression logVariable, String
methodName, Expression originalExpression);
}
+ /**
+ * A LoggingStrategy defines how to wire a new logger instance into an
existing class.
+ * It is meant to be used with the @Log family of annotations to allow you
to
+ * write your own Log annotation provider.
+ */
+ public interface LoggingStrategyV2 extends LoggingStrategy {
+ /**
+ * In this method, you are given a ClassNode, a field name and a
category name, and you must add a new Field
+ * onto the class. Return the result of the ClassNode.addField
operations.
+ *
+ * @param classNode the class that was originally annotated with
the Log transformation.
+ * @param fieldName the name of the logger field
+ * @param categoryName the name of the logging category
+ * @param fieldModifiers the modifiers (private, final, et. al.) of
the logger field
+ * @return the FieldNode instance that was created and added to the
class
+ */
+ FieldNode addLoggerFieldToClass(ClassNode classNode, String fieldName,
String categoryName, int fieldModifiers);
+ }
+
+ public abstract static class AbstractLoggingStrategyV2 extends
AbstractLoggingStrategy implements LoggingStrategyV2 {
+ protected AbstractLoggingStrategyV2(final GroovyClassLoader loader) {
+ super(loader);
+ }
+
+ protected AbstractLoggingStrategyV2() {
+ this(null);
+ }
+
+ @Override
+ public FieldNode addLoggerFieldToClass(ClassNode classNode, String
fieldName, String categoryName) {
+ throw new UnsupportedOperationException("This logger requires a
later version of Groovy");
+ }
+ }
+
public abstract static class AbstractLoggingStrategy implements
LoggingStrategy {
protected final GroovyClassLoader loader;
diff --git a/src/test/groovy/util/logging/CommonsTest.groovy
b/src/test/groovy/util/logging/CommonsTest.groovy
index b8d5acc..643defd 100644
--- a/src/test/groovy/util/logging/CommonsTest.groovy
+++ b/src/test/groovy/util/logging/CommonsTest.groovy
@@ -56,6 +56,80 @@ class CommonsTest extends GroovyTestCase {
}
}
+ void testExplicitPrivateFinalStaticLogFieldAppears() {
+ Class clazz = new GroovyClassLoader().parseClass('''
+ import static groovy.transform.options.Visibility.*
+ @groovy.transform.VisibilityOptions(value = PRIVATE)
+ @groovy.util.logging.Commons
+ class MyClass {
+ }
+ ''')
+
+ assert clazz.declaredFields.find { Field field ->
+ field.name == "log" &&
+ Modifier.isPrivate(field.getModifiers()) &&
+ Modifier.isStatic(field.getModifiers()) &&
+ Modifier.isTransient(field.getModifiers()) &&
+ Modifier.isFinal(field.getModifiers())
+ }
+ }
+
+ void testPackagePrivateFinalStaticLogFieldAppears() {
+ Class clazz = new GroovyClassLoader().parseClass('''
+ import static groovy.transform.options.Visibility.*
+ @groovy.transform.VisibilityOptions(value = PACKAGE_PRIVATE)
+ @groovy.util.logging.Commons
+ class MyClass {
+ }
+ ''')
+
+ assert clazz.declaredFields.find { Field field ->
+ field.name == "log" &&
+ !Modifier.isPrivate(field.getModifiers()) &&
+ !Modifier.isProtected(field.getModifiers()) &&
+ !Modifier.isPublic(field.getModifiers()) &&
+ Modifier.isStatic(field.getModifiers()) &&
+ Modifier.isTransient(field.getModifiers()) &&
+ Modifier.isFinal(field.getModifiers())
+ }
+ }
+
+ void testProtectedFinalStaticLogFieldAppears() {
+ Class clazz = new GroovyClassLoader().parseClass('''
+ import static groovy.transform.options.Visibility.*
+ @groovy.transform.VisibilityOptions(value = PROTECTED)
+ @groovy.util.logging.Commons
+ class MyClass {
+ }
+ ''')
+
+ assert clazz.declaredFields.find { Field field ->
+ field.name == "log" &&
+ Modifier.isProtected(field.getModifiers()) &&
+ Modifier.isStatic(field.getModifiers()) &&
+ Modifier.isTransient(field.getModifiers()) &&
+ Modifier.isFinal(field.getModifiers())
+ }
+ }
+
+ void testPublicFinalStaticLogFieldAppears() {
+ Class clazz = new GroovyClassLoader().parseClass('''
+ import static groovy.transform.options.Visibility.*
+ @groovy.transform.VisibilityOptions(value = PUBLIC)
+ @groovy.util.logging.Commons
+ class MyClass {
+ }
+ ''')
+
+ assert clazz.declaredFields.find { Field field ->
+ field.name == "log" &&
+ Modifier.isPublic(field.getModifiers()) &&
+ Modifier.isStatic(field.getModifiers()) &&
+ Modifier.isTransient(field.getModifiers()) &&
+ Modifier.isFinal(field.getModifiers())
+ }
+ }
+
void testPrivateFinalStaticNamedLogFieldAppears() {
Class clazz = new GroovyClassLoader().parseClass('''
@groovy.util.logging.Commons('logger')
@@ -110,7 +184,7 @@ class CommonsTest extends GroovyTestCase {
new MyClass().loggingMethod() ''')
clazz.newInstance().run()
-
+
String log = redirectedSystemOut.toString()
assert log.contains("error called")
assert log.contains("warn called")
@@ -129,7 +203,7 @@ class CommonsTest extends GroovyTestCase {
MyClass.loggingMethod()""")
clazz.newInstance().run()
-
+
String log = redirectedSystemOut.toString()
assert log.contains("(static) info called")
}
@@ -149,7 +223,7 @@ class CommonsTest extends GroovyTestCase {
new MyClass().loggingMethod() ''')
clazz.newInstance().run()
-
+
String log = redirectedSystemOut.toString()
assert log.contains("error called")
assert log.contains("warn called")
diff --git a/src/test/groovy/util/logging/Log4j2Test.groovy
b/src/test/groovy/util/logging/Log4j2Test.groovy
index 3d7b24c..0c09975 100644
--- a/src/test/groovy/util/logging/Log4j2Test.groovy
+++ b/src/test/groovy/util/logging/Log4j2Test.groovy
@@ -38,7 +38,7 @@ class Log4j2Test extends GroovyTestCase {
List<Map> events
boolean isLogGuarded = true
- Log4j2InterceptingAppender(String name, Filter filter, Layout<String>
layout){
+ Log4j2InterceptingAppender(String name, Filter filter, Layout<String>
layout) {
super(name, filter, layout)
this.events = new ArrayList<Map>()
}
@@ -94,6 +94,91 @@ class Log4j2Test extends GroovyTestCase {
}
}
+ void testExplicitPrivateFinalStaticLogFieldAppears() {
+ Class clazz = new GroovyClassLoader().parseClass('''
+ import static groovy.transform.options.Visibility.*
+ @groovy.transform.VisibilityOptions(value = PRIVATE)
+ @groovy.util.logging.Log4j2
+ class MyClass {
+ } ''')
+
+ assert clazz.declaredFields.find { Field field ->
+ field.name == "log" &&
+ Modifier.isPrivate(field.getModifiers()) &&
+ Modifier.isStatic(field.getModifiers()) &&
+ Modifier.isTransient(field.getModifiers()) &&
+ Modifier.isFinal(field.getModifiers())
+ }
+ }
+
+ void testPackagePrivateFinalStaticLogFieldAppears() {
+ Class clazz = new GroovyClassLoader().parseClass('''
+ import static groovy.transform.options.Visibility.*
+ @groovy.transform.VisibilityOptions(value = PACKAGE_PRIVATE)
+ @groovy.util.logging.Log4j2
+ class MyClass {
+ } ''')
+
+ assert clazz.declaredFields.find { Field field ->
+ field.name == "log" &&
+ !Modifier.isPrivate(field.getModifiers()) &&
+ !Modifier.isProtected(field.getModifiers()) &&
+ !Modifier.isPublic(field.getModifiers()) &&
+ Modifier.isStatic(field.getModifiers()) &&
+ Modifier.isTransient(field.getModifiers()) &&
+ Modifier.isFinal(field.getModifiers())
+ }
+ }
+
+ void testProtectedFinalStaticLogFieldAppears() {
+ Class clazz = new GroovyClassLoader().parseClass('''
+ import static groovy.transform.options.Visibility.*
+ @groovy.transform.VisibilityOptions(value = PROTECTED)
+ @groovy.util.logging.Log4j2
+ class MyClass {
+ } ''')
+
+ assert clazz.declaredFields.find { Field field ->
+ field.name == "log" &&
+ Modifier.isProtected(field.getModifiers()) &&
+ Modifier.isStatic(field.getModifiers()) &&
+ Modifier.isTransient(field.getModifiers()) &&
+ Modifier.isFinal(field.getModifiers())
+ }
+ }
+
+ void testPublicFinalStaticLogFieldAppears() {
+ Class clazz = new GroovyClassLoader().parseClass('''
+ import static groovy.transform.options.Visibility.*
+ @groovy.transform.VisibilityOptions(value = PUBLIC)
+ @groovy.util.logging.Log4j2
+ class MyClass {
+ } ''')
+
+ assert clazz.declaredFields.find { Field field ->
+ field.name == "log" &&
+ Modifier.isPublic(field.getModifiers()) &&
+ Modifier.isStatic(field.getModifiers()) &&
+ Modifier.isTransient(field.getModifiers()) &&
+ Modifier.isFinal(field.getModifiers())
+ }
+ }
+
+ void testUnknownAccessPrivateFinalStaticLogFieldAppears() {
+ Class clazz = new GroovyClassLoader().parseClass('''
+ @groovy.util.logging.Log4j2
+ class MyClass {
+ } ''')
+
+ assert clazz.declaredFields.find { Field field ->
+ field.name == "log" &&
+ Modifier.isPrivate(field.getModifiers()) &&
+ Modifier.isStatic(field.getModifiers()) &&
+ Modifier.isTransient(field.getModifiers()) &&
+ Modifier.isFinal(field.getModifiers())
+ }
+ }
+
void testClassAlreadyHasLogField() {
shouldFail(RuntimeException) {
Class clazz = new GroovyClassLoader().parseClass('''
@@ -259,7 +344,7 @@ class Log4j2Test extends GroovyTestCase {
log.error("error called")
}
}""")
-
+
clazz.newInstance().loggingMethod()
assert appenderForCustomCategory.getEvents().size() == 1
diff --git a/src/test/groovy/util/logging/Log4jTest.groovy
b/src/test/groovy/util/logging/Log4jTest.groovy
index febc05f..3ed8c25 100644
--- a/src/test/groovy/util/logging/Log4jTest.groovy
+++ b/src/test/groovy/util/logging/Log4jTest.groovy
@@ -62,6 +62,76 @@ class Log4jTest extends GroovyTestCase {
}
}
+ void testExplicitPrivateFinalStaticLogFieldAppears() {
+ Class clazz = new GroovyClassLoader().parseClass('''
+ import static groovy.transform.options.Visibility.*
+ @groovy.transform.VisibilityOptions(value = PRIVATE)
+ @groovy.util.logging.Log4j
+ class MyClass {
+ } ''')
+
+ assert clazz.declaredFields.find { Field field ->
+ field.name == "log" &&
+ Modifier.isPrivate(field.getModifiers()) &&
+ Modifier.isStatic(field.getModifiers()) &&
+ Modifier.isTransient(field.getModifiers()) &&
+ Modifier.isFinal(field.getModifiers())
+ }
+ }
+
+ void testPackagePrivateFinalStaticLogFieldAppears() {
+ Class clazz = new GroovyClassLoader().parseClass('''
+ import static groovy.transform.options.Visibility.*
+ @groovy.transform.VisibilityOptions(value = PACKAGE_PRIVATE)
+ @groovy.util.logging.Log4j
+ class MyClass {
+ } ''')
+
+ assert clazz.declaredFields.find { Field field ->
+ field.name == "log" &&
+ !Modifier.isPrivate(field.getModifiers()) &&
+ !Modifier.isProtected(field.getModifiers()) &&
+ !Modifier.isPublic(field.getModifiers()) &&
+ Modifier.isStatic(field.getModifiers()) &&
+ Modifier.isTransient(field.getModifiers()) &&
+ Modifier.isFinal(field.getModifiers())
+ }
+ }
+
+ void testProtectedFinalStaticLogFieldAppears() {
+ Class clazz = new GroovyClassLoader().parseClass('''
+ import static groovy.transform.options.Visibility.*
+ @groovy.transform.VisibilityOptions(value = PROTECTED)
+ @groovy.util.logging.Log4j
+ class MyClass {
+ } ''')
+
+ assert clazz.declaredFields.find { Field field ->
+ field.name == "log" &&
+ Modifier.isProtected(field.getModifiers()) &&
+ Modifier.isStatic(field.getModifiers()) &&
+ Modifier.isTransient(field.getModifiers()) &&
+ Modifier.isFinal(field.getModifiers())
+ }
+ }
+
+ void testPublicFinalStaticLogFieldAppears() {
+ Class clazz = new GroovyClassLoader().parseClass('''
+ import static groovy.transform.options.Visibility.*
+ @groovy.transform.VisibilityOptions(value = PUBLIC)
+ @groovy.util.logging.Log4j
+ class MyClass {
+ } ''')
+
+ assert clazz.declaredFields.find { Field field ->
+ field.name == "log" &&
+ Modifier.isPublic(field.getModifiers()) &&
+ Modifier.isStatic(field.getModifiers()) &&
+ Modifier.isTransient(field.getModifiers()) &&
+ Modifier.isFinal(field.getModifiers())
+ }
+ }
+
void testClassAlreadyHasLogField() {
shouldFail {
diff --git a/src/test/groovy/util/logging/LogTest.groovy
b/src/test/groovy/util/logging/LogTest.groovy
index a52788a..57f7929 100644
--- a/src/test/groovy/util/logging/LogTest.groovy
+++ b/src/test/groovy/util/logging/LogTest.groovy
@@ -61,6 +61,76 @@ class LogTest extends GroovyTestCase {
}
}
+ void testExplicitPrivateFinalStaticLogFieldAppears() {
+ Class clazz = new GroovyClassLoader().parseClass('''
+ import static groovy.transform.options.Visibility.*
+ @groovy.transform.VisibilityOptions(value = PRIVATE)
+ @groovy.util.logging.Log
+ class MyClass {
+ } ''')
+
+ assert clazz.declaredFields.find { Field field ->
+ field.name == "log" &&
+ Modifier.isPrivate(field.getModifiers()) &&
+ Modifier.isStatic(field.getModifiers()) &&
+ Modifier.isTransient(field.getModifiers()) &&
+ Modifier.isFinal(field.getModifiers())
+ }
+ }
+
+ void testPackagePrivateFinalStaticLogFieldAppears() {
+ Class clazz = new GroovyClassLoader().parseClass('''
+ import static groovy.transform.options.Visibility.*
+ @groovy.transform.VisibilityOptions(value = PACKAGE_PRIVATE)
+ @groovy.util.logging.Log
+ class MyClass {
+ } ''')
+
+ assert clazz.declaredFields.find { Field field ->
+ field.name == "log" &&
+ !Modifier.isPrivate(field.getModifiers()) &&
+ !Modifier.isProtected(field.getModifiers()) &&
+ !Modifier.isPublic(field.getModifiers()) &&
+ Modifier.isStatic(field.getModifiers()) &&
+ Modifier.isTransient(field.getModifiers()) &&
+ Modifier.isFinal(field.getModifiers())
+ }
+ }
+
+ void testProtectedFinalStaticLogFieldAppears() {
+ Class clazz = new GroovyClassLoader().parseClass('''
+ import static groovy.transform.options.Visibility.*
+ @groovy.transform.VisibilityOptions(value = PROTECTED)
+ @groovy.util.logging.Log
+ class MyClass {
+ } ''')
+
+ assert clazz.declaredFields.find { Field field ->
+ field.name == "log" &&
+ Modifier.isProtected(field.getModifiers()) &&
+ Modifier.isStatic(field.getModifiers()) &&
+ Modifier.isTransient(field.getModifiers()) &&
+ Modifier.isFinal(field.getModifiers())
+ }
+ }
+
+ void testPublicFinalStaticLogFieldAppears() {
+ Class clazz = new GroovyClassLoader().parseClass('''
+ import static groovy.transform.options.Visibility.*
+ @groovy.transform.VisibilityOptions(value = PUBLIC)
+ @groovy.util.logging.Log
+ class MyClass {
+ } ''')
+
+ assert clazz.declaredFields.find { Field field ->
+ field.name == "log" &&
+ Modifier.isPublic(field.getModifiers()) &&
+ Modifier.isStatic(field.getModifiers()) &&
+ Modifier.isTransient(field.getModifiers()) &&
+ Modifier.isFinal(field.getModifiers())
+ }
+ }
+
void testClassAlreadyHasLogField() {
shouldFail {
@@ -312,7 +382,8 @@ class LogTest extends GroovyTestCase {
}
}
[email protected] class LoggerSpy extends Logger {
[email protected]
+class LoggerSpy extends Logger {
String severeParameter = null
String warningParameter = null
diff --git a/src/test/groovy/util/logging/Slf4jTest.groovy
b/src/test/groovy/util/logging/Slf4jTest.groovy
index 6a6324b..52e113f 100644
--- a/src/test/groovy/util/logging/Slf4jTest.groovy
+++ b/src/test/groovy/util/logging/Slf4jTest.groovy
@@ -74,6 +74,76 @@ class Slf4jTest extends GroovyTestCase {
}
}
+ void testExplicitPrivateFinalStaticLogFieldAppears() {
+ Class clazz = new GroovyClassLoader().parseClass('''
+ import static groovy.transform.options.Visibility.*
+ @groovy.transform.VisibilityOptions(value = PRIVATE)
+ @groovy.util.logging.Slf4j
+ class MyClass {
+ } ''')
+
+ assert clazz.declaredFields.find { Field field ->
+ field.name == "log" &&
+ Modifier.isPrivate(field.getModifiers()) &&
+ Modifier.isStatic(field.getModifiers()) &&
+ Modifier.isTransient(field.getModifiers()) &&
+ Modifier.isFinal(field.getModifiers())
+ }
+ }
+
+ void testPackagePrivateFinalStaticLogFieldAppears() {
+ Class clazz = new GroovyClassLoader().parseClass('''
+ import static groovy.transform.options.Visibility.*
+ @groovy.transform.VisibilityOptions(value = PACKAGE_PRIVATE)
+ @groovy.util.logging.Slf4j
+ class MyClass {
+ } ''')
+
+ assert clazz.declaredFields.find { Field field ->
+ field.name == "log" &&
+ !Modifier.isPrivate(field.getModifiers()) &&
+ !Modifier.isProtected(field.getModifiers()) &&
+ !Modifier.isPublic(field.getModifiers()) &&
+ Modifier.isStatic(field.getModifiers()) &&
+ Modifier.isTransient(field.getModifiers()) &&
+ Modifier.isFinal(field.getModifiers())
+ }
+ }
+
+ void testProtectedFinalStaticLogFieldAppears() {
+ Class clazz = new GroovyClassLoader().parseClass('''
+ import static groovy.transform.options.Visibility.*
+ @groovy.transform.VisibilityOptions(value = PROTECTED)
+ @groovy.util.logging.Slf4j
+ class MyClass {
+ } ''')
+
+ assert clazz.declaredFields.find { Field field ->
+ field.name == "log" &&
+ Modifier.isProtected(field.getModifiers()) &&
+ Modifier.isStatic(field.getModifiers()) &&
+ Modifier.isTransient(field.getModifiers()) &&
+ Modifier.isFinal(field.getModifiers())
+ }
+ }
+
+ void testPublicFinalStaticLogFieldAppears() {
+ Class clazz = new GroovyClassLoader().parseClass('''
+ import static groovy.transform.options.Visibility.*
+ @groovy.transform.VisibilityOptions(value = PUBLIC)
+ @groovy.util.logging.Slf4j
+ class MyClass {
+ } ''')
+
+ assert clazz.declaredFields.find { Field field ->
+ field.name == "log" &&
+ Modifier.isPublic(field.getModifiers()) &&
+ Modifier.isStatic(field.getModifiers()) &&
+ Modifier.isTransient(field.getModifiers()) &&
+ Modifier.isFinal(field.getModifiers())
+ }
+ }
+
void testPrivateFinalStaticNamedLogFieldAppears() {
Class clazz = new GroovyClassLoader().parseClass('''
@groovy.util.logging.Slf4j('logger')