You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tomcat.apache.org by re...@apache.org on 2021/04/19 08:50:21 UTC
[tomcat] branch master updated: Parse annotations on fields or
methods
This is an automated email from the ASF dual-hosted git repository.
remm pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/tomcat.git
The following commit(s) were added to refs/heads/master by this push:
new 7ff693d Parse annotations on fields or methods
7ff693d is described below
commit 7ff693d5075ddfb2581fe7df911fc686dc535124
Author: remm <re...@apache.org>
AuthorDate: Mon Apr 19 10:49:04 2021 +0200
Parse annotations on fields or methods
BZ 65244: Use that info for HandlesTypes since it is supposed to also
include annotations used on fields and methods.
---
.../org/apache/catalina/startup/ContextConfig.java | 2 +-
.../tomcat/util/bcel/classfile/ClassParser.java | 43 ++++++++++++++++------
.../tomcat/util/bcel/classfile/JavaClass.java | 35 +++++++++++++++++-
.../apache/tomcat/util/bcel/classfile/Utility.java | 13 -------
webapps/docs/changelog.xml | 4 ++
5 files changed, 71 insertions(+), 26 deletions(-)
diff --git a/java/org/apache/catalina/startup/ContextConfig.java b/java/org/apache/catalina/startup/ContextConfig.java
index bc68499..058d412 100644
--- a/java/org/apache/catalina/startup/ContextConfig.java
+++ b/java/org/apache/catalina/startup/ContextConfig.java
@@ -2426,7 +2426,7 @@ public class ContextConfig implements LifecycleListener {
}
if (handlesTypesAnnotations) {
- AnnotationEntry[] annotationEntries = javaClass.getAnnotationEntries();
+ AnnotationEntry[] annotationEntries = javaClass.getAllAnnotationEntries();
if (annotationEntries != null) {
for (Map.Entry<Class<?>, Set<ServletContainerInitializer>> entry :
typeInitializerMap.entrySet()) {
diff --git a/java/org/apache/tomcat/util/bcel/classfile/ClassParser.java b/java/org/apache/tomcat/util/bcel/classfile/ClassParser.java
index 303be90..89dab31 100644
--- a/java/org/apache/tomcat/util/bcel/classfile/ClassParser.java
+++ b/java/org/apache/tomcat/util/bcel/classfile/ClassParser.java
@@ -22,6 +22,8 @@ import java.io.DataInput;
import java.io.DataInputStream;
import java.io.IOException;
import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.List;
import org.apache.tomcat.util.bcel.Const;
@@ -47,6 +49,7 @@ public final class ClassParser {
private String[] interfaceNames; // Names of implemented interfaces
private ConstantPool constantPool; // collection of constants
private Annotations runtimeVisibleAnnotations; // "RuntimeVisibleAnnotations" attribute defined in the class
+ private List<Annotations> runtimeVisibleMethodOfFieldAnnotations; // "RuntimeVisibleAnnotations" attribute defined elsewhere
private static final int BUFSIZE = 8192;
private static final String[] INTERFACES_EMPTY_ARRAY = new String[0];
@@ -91,41 +94,49 @@ public final class ClassParser {
// Read class methods, i.e., the functions in the class
readMethods();
// Read class attributes
- readAttributes();
+ readAttributes(false);
// Return the information we have gathered in a new object
return new JavaClass(class_name, superclassName,
accessFlags, constantPool, interfaceNames,
- runtimeVisibleAnnotations);
+ runtimeVisibleAnnotations, runtimeVisibleMethodOfFieldAnnotations);
}
/**
* Reads information about the attributes of the class.
+ * @param fieldOrMethod false if processing a class
* @throws IOException
* @throws ClassFormatException
*/
- private void readAttributes() throws IOException, ClassFormatException {
+ private void readAttributes(boolean fieldOrMethod) throws IOException, ClassFormatException {
final int attributes_count = dataInputStream.readUnsignedShort();
for (int i = 0; i < attributes_count; i++) {
ConstantUtf8 c;
String name;
int name_index;
int length;
- // Get class name from constant pool via `name_index' indirection
+ // Get class name from constant pool via 'name_index' indirection
name_index = dataInputStream.readUnsignedShort();
c = (ConstantUtf8) constantPool.getConstant(name_index,
Const.CONSTANT_Utf8);
name = c.getBytes();
// Length of data in bytes
length = dataInputStream.readInt();
-
if (name.equals("RuntimeVisibleAnnotations")) {
- if (runtimeVisibleAnnotations != null) {
- throw new ClassFormatException(
- "RuntimeVisibleAnnotations attribute is not allowed more than once in a class file");
+ if (fieldOrMethod) {
+ Annotations fieldOrMethodAnnotations = new Annotations(dataInputStream, constantPool);
+ if (runtimeVisibleMethodOfFieldAnnotations == null) {
+ runtimeVisibleMethodOfFieldAnnotations = new ArrayList<>();
+ }
+ runtimeVisibleMethodOfFieldAnnotations.add(fieldOrMethodAnnotations);
+ } else {
+ if (runtimeVisibleAnnotations != null) {
+ throw new ClassFormatException(
+ "RuntimeVisibleAnnotations attribute is not allowed more than once in a class file");
+ }
+ runtimeVisibleAnnotations = new Annotations(dataInputStream, constantPool);
}
- runtimeVisibleAnnotations = new Annotations(dataInputStream, constantPool);
} else {
// All other attributes are skipped
Utility.skipFully(dataInputStream, length);
@@ -183,7 +194,12 @@ public final class ClassParser {
private void readFields() throws IOException, ClassFormatException {
final int fields_count = dataInputStream.readUnsignedShort();
for (int i = 0; i < fields_count; i++) {
- Utility.swallowFieldOrMethod(dataInputStream);
+ // file.readUnsignedShort(); // Unused access flags
+ // file.readUnsignedShort(); // name index
+ // file.readUnsignedShort(); // signature index
+ Utility.skipFully(dataInputStream, 6);
+
+ readAttributes(true);
}
}
@@ -229,7 +245,12 @@ public final class ClassParser {
private void readMethods() throws IOException, ClassFormatException {
final int methods_count = dataInputStream.readUnsignedShort();
for (int i = 0; i < methods_count; i++) {
- Utility.swallowFieldOrMethod(dataInputStream);
+ // file.readUnsignedShort(); // Unused access flags
+ // file.readUnsignedShort(); // name index
+ // file.readUnsignedShort(); // signature index
+ Utility.skipFully(dataInputStream, 6);
+
+ readAttributes(true);
}
}
diff --git a/java/org/apache/tomcat/util/bcel/classfile/JavaClass.java b/java/org/apache/tomcat/util/bcel/classfile/JavaClass.java
index 46473ad..14ef3a1 100644
--- a/java/org/apache/tomcat/util/bcel/classfile/JavaClass.java
+++ b/java/org/apache/tomcat/util/bcel/classfile/JavaClass.java
@@ -17,6 +17,9 @@
*/
package org.apache.tomcat.util.bcel.classfile;
+import java.util.HashMap;
+import java.util.List;
+
/**
* Represents a Java class, i.e., the data structures, constant pool,
* fields, methods and commands contained in a Java .class file.
@@ -32,6 +35,7 @@ public class JavaClass {
private final String superclassName;
private final String[] interfaceNames;
private final Annotations runtimeVisibleAnnotations; // "RuntimeVisibleAnnotations" attribute defined in the class
+ private final List<Annotations> runtimeVisibleMethodOfFieldAnnotations; // "RuntimeVisibleAnnotations" attribute defined elsewhere
/**
* Constructor gets all contents as arguments.
@@ -42,12 +46,14 @@ public class JavaClass {
* @param constant_pool Array of constants
* @param interfaceNames Implemented interfaces
* @param runtimeVisibleAnnotations "RuntimeVisibleAnnotations" attribute defined on the Class, or null
+ * @param runtimeVisibleMethodOfFieldAnnotations "RuntimeVisibleAnnotations" attribute defined on the fields or methids, or null
*/
JavaClass(final String className, final String superclassName,
final int accessFlags, final ConstantPool constant_pool, final String[] interfaceNames,
- final Annotations runtimeVisibleAnnotations) {
+ final Annotations runtimeVisibleAnnotations, final List<Annotations> runtimeVisibleMethodOfFieldAnnotations) {
this.accessFlags = accessFlags;
this.runtimeVisibleAnnotations = runtimeVisibleAnnotations;
+ this.runtimeVisibleMethodOfFieldAnnotations = runtimeVisibleMethodOfFieldAnnotations;
this.className = className;
this.superclassName = superclassName;
this.interfaceNames = interfaceNames;
@@ -74,6 +80,33 @@ public class JavaClass {
}
/**
+ * Return annotations entries from "RuntimeVisibleAnnotations" attribute on
+ * the class, fields or methods if there is any.
+ *
+ * @return An array of entries or {@code null}
+ */
+ public AnnotationEntry[] getAllAnnotationEntries() {
+ HashMap<String, AnnotationEntry> annotationEntries = new HashMap<>();
+ if (runtimeVisibleAnnotations != null) {
+ for (AnnotationEntry annotationEntry : runtimeVisibleAnnotations.getAnnotationEntries()) {
+ annotationEntries.put(annotationEntry.getAnnotationType(), annotationEntry);
+ }
+ }
+ if (runtimeVisibleMethodOfFieldAnnotations != null) {
+ for (Annotations annotations : runtimeVisibleMethodOfFieldAnnotations.toArray(new Annotations[0])) {
+ for (AnnotationEntry annotationEntry : annotations.getAnnotationEntries()) {
+ annotationEntries.putIfAbsent(annotationEntry.getAnnotationType(), annotationEntry);
+ }
+ }
+ }
+ if (annotationEntries.isEmpty()) {
+ return null;
+ } else {
+ return annotationEntries.values().toArray(new AnnotationEntry[0]);
+ }
+ }
+
+ /**
* @return Class name.
*/
public String getClassName() {
diff --git a/java/org/apache/tomcat/util/bcel/classfile/Utility.java b/java/org/apache/tomcat/util/bcel/classfile/Utility.java
index 1097b01..dc0a09b 100644
--- a/java/org/apache/tomcat/util/bcel/classfile/Utility.java
+++ b/java/org/apache/tomcat/util/bcel/classfile/Utility.java
@@ -62,19 +62,6 @@ final class Utility {
}
}
- static void swallowFieldOrMethod(final DataInput file)
- throws IOException {
- // file.readUnsignedShort(); // Unused access flags
- // file.readUnsignedShort(); // name index
- // file.readUnsignedShort(); // signature index
- skipFully(file, 6);
-
- int attributes_count = file.readUnsignedShort();
- for (int i = 0; i < attributes_count; i++) {
- swallowAttribute(file);
- }
- }
-
static void swallowAttribute(final DataInput file)
throws IOException {
//file.readUnsignedShort(); // Unused name index
diff --git a/webapps/docs/changelog.xml b/webapps/docs/changelog.xml
index 43bd12e..47887cd 100644
--- a/webapps/docs/changelog.xml
+++ b/webapps/docs/changelog.xml
@@ -118,6 +118,10 @@
<bug>65235</bug>: Add missing attributes to the MBean descriptor file
for the <code>RemoteIpValve</code>. (markt)
</fix>
+ <fix>
+ <bug>65244</bug>: HandlesTypes should include classes that use
+ the specified annotation types on fields or methods. (remm)
+ </fix>
</changelog>
</subsection>
<subsection name="Jasper">
---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org