mirror of
https://github.com/jlengrand/helidon.git
synced 2026-03-10 08:21:17 +00:00
Upgrade svm, annotation for reflection (#2070)
* Upgrade svm libraries. Annotation for reflection in native image. Signed-off-by: Tomas Langer <tomas.langer@oracle.com> * Missed required class. Signed-off-by: Tomas Langer <tomas.langer@oracle.com> Signed-off-by: Tomas Langer <tomas.langer@oracle.com>
This commit is contained in:
39
common/common/src/main/java/io/helidon/common/Reflected.java
Normal file
39
common/common/src/main/java/io/helidon/common/Reflected.java
Normal file
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright (c) 2020 Oracle and/or its affiliates.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.helidon.common;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* A type annotated with this annotation will be added to native image with reflection support for all methods
|
||||
* and fields (including private).
|
||||
* A method or field annotated with this method will be added for reflection.
|
||||
* <p>
|
||||
* This is an alternative to GraalVM native-image's {@code reflect-config.json} file, specific to Helidon.
|
||||
* Processing of this annotation requires {@code io.helidon.integrations.graal:helidon-graal-native-image-extension}
|
||||
* on the classpath when building native image.
|
||||
* <p>
|
||||
* Constructors annotated with this annotation would only be added for reflection if either a field
|
||||
* or a method is annotated as well (this is current limitation of API of native image).
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD, ElementType.CONSTRUCTOR})
|
||||
public @interface Reflected {
|
||||
}
|
||||
4
dependencies/pom.xml
vendored
4
dependencies/pom.xml
vendored
@@ -51,7 +51,7 @@
|
||||
<version.lib.failsafe>2.3.1</version.lib.failsafe>
|
||||
<version.lib.google-api-client>1.30.5</version.lib.google-api-client>
|
||||
<version.lib.google-error-prone>2.3.3</version.lib.google-error-prone>
|
||||
<version.lib.graalvm>19.2.0</version.lib.graalvm>
|
||||
<version.lib.graalvm>20.0.0</version.lib.graalvm>
|
||||
<version.lib.grpc>1.27.1</version.lib.grpc>
|
||||
<version.lib.guava>28.1-jre</version.lib.guava>
|
||||
<version.lib.h2>1.4.199</version.lib.h2>
|
||||
@@ -914,7 +914,7 @@
|
||||
<version>${version.lib.graalvm}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.oracle.substratevm</groupId>
|
||||
<groupId>org.graalvm.nativeimage</groupId>
|
||||
<artifactId>svm</artifactId>
|
||||
<version>${version.lib.graalvm}</version>
|
||||
</dependency>
|
||||
|
||||
@@ -15,11 +15,13 @@
|
||||
*/
|
||||
package io.helidon.examples.dbclient.pokemons;
|
||||
|
||||
import io.helidon.common.Reflected;
|
||||
|
||||
/**
|
||||
* POJO representing Pokemon.
|
||||
*/
|
||||
@Reflected
|
||||
public class Pokemon {
|
||||
|
||||
private int id;
|
||||
private String name;
|
||||
private int idType;
|
||||
|
||||
@@ -36,7 +36,7 @@ import io.helidon.webserver.WebServer;
|
||||
*/
|
||||
public final class PokemonMain {
|
||||
|
||||
/** MongoDB configuration. Default configuration file {@code appliaction.yaml} contains MySQL/JDBC configuration. */
|
||||
/** MongoDB configuration. Default configuration file {@code appliaction.yaml} contains JDBC configuration. */
|
||||
private static final String MONGO_CFG = "mongo.yaml";
|
||||
|
||||
/** Whether MongoDB support is selected. */
|
||||
@@ -63,7 +63,7 @@ public final class PokemonMain {
|
||||
System.out.println("MongoDB database selected");
|
||||
mongo = true;
|
||||
} else {
|
||||
System.out.println("MySQL/JDBC database selected");
|
||||
System.out.println("JDBC database selected");
|
||||
mongo = false;
|
||||
}
|
||||
startServer();
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
[{
|
||||
"name" : "io.helidon.examples.dbclient.pokemons.Pokemon",
|
||||
"allDeclaredConstructors" : true,
|
||||
"allPublicConstructors" : true,
|
||||
"allDeclaredMethods" : true,
|
||||
"allPublicMethods" : true,
|
||||
"allDeclaredFields" : true,
|
||||
"allPublicFields" : true
|
||||
}]
|
||||
@@ -31,7 +31,7 @@
|
||||
|
||||
<properties>
|
||||
<!--
|
||||
To build javadocs we need to have a valid module-info file. But com.oracle.substratevm:svm appears
|
||||
To build javadocs we need to have a valid module-info file. But org.graalvm.nativeimage:svm appears
|
||||
to have a bad module-info. So for now we skip generating javadocs.
|
||||
-->
|
||||
<maven.javadoc.skip>true</maven.javadoc.skip>
|
||||
@@ -44,7 +44,7 @@
|
||||
<artifactId>h2</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.oracle.substratevm</groupId>
|
||||
<groupId>org.graalvm.nativeimage</groupId>
|
||||
<artifactId>svm</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
{
|
||||
"classes": [
|
||||
"org.hibernate.dialect.Oracle10gDialect"
|
||||
"org.hibernate.dialect.Oracle10gDialect",
|
||||
"oracle.jdbc.logging.annotations.Supports",
|
||||
"oracle.jdbc.logging.annotations.Feature"
|
||||
]
|
||||
}
|
||||
|
||||
@@ -57,7 +57,7 @@
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.oracle.substratevm</groupId>
|
||||
<groupId>org.graalvm.nativeimage</groupId>
|
||||
<artifactId>svm</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
|
||||
<properties>
|
||||
<!--
|
||||
To build javadocs we need to have a valid module-info file. But com.oracle.substratevm:svm appears
|
||||
To build javadocs we need to have a valid module-info file. But org.graalvm.nativeimage:svm appears
|
||||
to have a bad module-info. So for now we skip generating javadocs.
|
||||
-->
|
||||
<maven.javadoc.skip>true</maven.javadoc.skip>
|
||||
@@ -55,7 +55,7 @@
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.oracle.substratevm</groupId>
|
||||
<groupId>org.graalvm.nativeimage</groupId>
|
||||
<artifactId>svm</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
@@ -26,13 +26,14 @@ import java.net.URL;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Enumeration;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import javax.json.Json;
|
||||
import javax.json.JsonArray;
|
||||
@@ -42,6 +43,7 @@ import javax.json.stream.JsonParsingException;
|
||||
|
||||
import io.helidon.common.HelidonFeatures;
|
||||
import io.helidon.common.LogConfig;
|
||||
import io.helidon.common.Reflected;
|
||||
import io.helidon.config.mp.MpConfigProviderResolver;
|
||||
|
||||
import com.oracle.svm.core.annotate.AutomaticFeature;
|
||||
@@ -82,7 +84,6 @@ public class HelidonReflectionFeature implements Feature {
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
//LogConfig.initClass();
|
||||
|
||||
// make sure we print all the warnings for native image
|
||||
HelidonFeatures.nativeBuildTime(classLoader);
|
||||
@@ -107,6 +108,10 @@ public class HelidonReflectionFeature implements Feature {
|
||||
// JPA Entity registration
|
||||
processEntity(context);
|
||||
|
||||
// all classes, fields and methods annotated with @Reflected
|
||||
addAnnotatedWithReflected(context);
|
||||
|
||||
// and finally register with native image
|
||||
registerForReflection(context);
|
||||
}
|
||||
|
||||
@@ -115,6 +120,75 @@ public class HelidonReflectionFeature implements Feature {
|
||||
MpConfigProviderResolver.buildTimeEnd();
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private void addAnnotatedWithReflected(BeforeAnalysisContext context) {
|
||||
FeatureImpl.BeforeAnalysisAccessImpl access = context.access();
|
||||
|
||||
// want to make sure we use the correct classloader
|
||||
Class<? extends Annotation> annotation = (Class<? extends Annotation>) access.findClassByName(Reflected.class.getName());
|
||||
|
||||
traceParsing(() -> "Looking up annotated by " + annotation.getName());
|
||||
|
||||
// classes
|
||||
access.findAnnotatedClasses(annotation)
|
||||
.forEach(it -> {
|
||||
traceParsing(() -> " class " + it.getName());
|
||||
context.register(it).addAll();
|
||||
});
|
||||
|
||||
// methods
|
||||
access.findAnnotatedMethods(annotation)
|
||||
.forEach(it -> {
|
||||
if (context.register(it.getDeclaringClass()).add(it)) {
|
||||
traceParsing(() -> " method " + it);
|
||||
}
|
||||
});
|
||||
|
||||
// fields
|
||||
access.findAnnotatedFields(annotation)
|
||||
.forEach(it -> {
|
||||
if (context.register(it.getDeclaringClass()).add(it)) {
|
||||
traceParsing(() -> " field " + it);
|
||||
}
|
||||
});
|
||||
|
||||
// attempt to add annotated constructors if any other field is registered
|
||||
context.toRegister()
|
||||
.forEach(register -> addAnnotatedConstructors(register, annotation));
|
||||
}
|
||||
|
||||
private void addAnnotatedConstructors(Register register, Class<? extends Annotation> annotation) {
|
||||
// only do this if constructors is empty, as otherwise they are already all there
|
||||
if (register.constructors.isEmpty()) {
|
||||
try {
|
||||
Constructor<?>[] constructors = register.clazz.getConstructors();
|
||||
for (Constructor<?> constructor : constructors) {
|
||||
if (constructor.getAnnotation(annotation) != null) {
|
||||
if (register.add(constructor)) {
|
||||
traceParsing(() -> " constructor " + constructor);
|
||||
}
|
||||
}
|
||||
}
|
||||
constructors = register.clazz.getDeclaredConstructors();
|
||||
for (Constructor<?> constructor : constructors) {
|
||||
if (constructor.getAnnotation(annotation) != null) {
|
||||
if (register.add(constructor)) {
|
||||
traceParsing(() -> " constructor " + constructor);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (NoClassDefFoundError e) {
|
||||
if (TRACE) {
|
||||
System.out.println("Constructors of "
|
||||
+ register.clazz.getName()
|
||||
+ " not added to reflection, as a type is not on classpath: "
|
||||
+ e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private void processEntity(BeforeAnalysisContext context) {
|
||||
final Class<? extends Annotation> annotation = (Class<? extends Annotation>) context.access()
|
||||
.findClassByName(ENTITY_ANNOTATION_CLASS_NAME);
|
||||
@@ -131,7 +205,7 @@ public class HelidonReflectionFeature implements Feature {
|
||||
if (!Modifier.isPublic(declaredField.getModifiers()) && declaredField.getAnnotations().length == 0) {
|
||||
RuntimeReflection.register(declaredField);
|
||||
if (TRACE) {
|
||||
System.out.println(" non annotaded field " + declaredField);
|
||||
System.out.println(" non annotated field " + declaredField);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -168,9 +242,8 @@ public class HelidonReflectionFeature implements Feature {
|
||||
});
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private void registerForReflection(BeforeAnalysisContext context) {
|
||||
Set<Class<?>> toRegister = context.toRegister();
|
||||
Collection<Register> toRegister = context.toRegister();
|
||||
|
||||
if (TRACE) {
|
||||
System.out.println("***********************************");
|
||||
@@ -179,134 +252,73 @@ public class HelidonReflectionFeature implements Feature {
|
||||
}
|
||||
|
||||
// register for reflection
|
||||
for (Class<?> aClass : toRegister) {
|
||||
if (TRACE) {
|
||||
System.out.println("Registering " + aClass.getName() + " for reflection");
|
||||
}
|
||||
RuntimeReflection.register(aClass);
|
||||
for (Register register : toRegister) {
|
||||
register(register.clazz);
|
||||
|
||||
registerMethods(aClass);
|
||||
|
||||
if (aClass.isInterface()) {
|
||||
continue;
|
||||
if (!register.clazz.isInterface()) {
|
||||
register.fields.forEach(this::register);
|
||||
register.constructors.forEach(this::register);
|
||||
}
|
||||
|
||||
registerFields(aClass);
|
||||
|
||||
registerConstructors(aClass);
|
||||
register.methods.forEach(this::register);
|
||||
}
|
||||
}
|
||||
|
||||
private void registerConstructors(Class<?> aClass) {
|
||||
try {
|
||||
// find all public constructors
|
||||
Set<Constructor<?>> constructors = new LinkedHashSet<>(Arrays.asList(aClass.getConstructors()));
|
||||
// add all declared
|
||||
constructors.addAll(Arrays.asList(aClass.getDeclaredConstructors()));
|
||||
|
||||
for (Constructor<?> constructor : constructors) {
|
||||
RuntimeReflection.register(constructor);
|
||||
if (TRACE) {
|
||||
System.out.println(" " + constructor);
|
||||
}
|
||||
}
|
||||
} catch (NoClassDefFoundError e) {
|
||||
if (TRACE) {
|
||||
System.out.println("Constructors of "
|
||||
+ aClass.getName()
|
||||
+ " not added to reflection, as a type is not on classpath: "
|
||||
+ e.getMessage());
|
||||
}
|
||||
private void register(Constructor<?> constructor) {
|
||||
if (TRACE) {
|
||||
System.out.println(" " + constructor.getDeclaringClass().getSimpleName()
|
||||
+ "("
|
||||
+ params(constructor.getParameterTypes())
|
||||
+ ")");
|
||||
}
|
||||
RuntimeReflection.register(constructor);
|
||||
}
|
||||
|
||||
private void registerMethods(Class<?> aClass) {
|
||||
try {
|
||||
Method[] methods = aClass.getMethods();
|
||||
for (Method method : methods) {
|
||||
boolean register = true;
|
||||
|
||||
// we do not want wait, notify etc
|
||||
register = (method.getDeclaringClass() != Object.class);
|
||||
|
||||
if (register) {
|
||||
// we do not want toString(), hashCode(), equals(java.lang.Object)
|
||||
switch (method.getName()) {
|
||||
case "hashCode":
|
||||
case "toString":
|
||||
register = !hasParams(method);
|
||||
break;
|
||||
case "equals":
|
||||
register = !hasParams(method, Object.class);
|
||||
break;
|
||||
default:
|
||||
// do nothing
|
||||
}
|
||||
}
|
||||
|
||||
if (register) {
|
||||
if (TRACE) {
|
||||
System.out.println(" " + method.getName() + "(" + Arrays.toString(method.getParameterTypes()) + ")");
|
||||
}
|
||||
RuntimeReflection.register(method);
|
||||
}
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
if (TRACE) {
|
||||
System.out.println(" Cannot register methods of " + aClass.getName() + ": " + e.getClass().getName() + ": " + e
|
||||
.getMessage());
|
||||
}
|
||||
private String params(Class<?>[] parameterTypes) {
|
||||
if (parameterTypes.length == 0) {
|
||||
return "";
|
||||
}
|
||||
return Arrays.stream(parameterTypes)
|
||||
.map(Class::getName)
|
||||
.collect(Collectors.joining(", "));
|
||||
}
|
||||
|
||||
private boolean hasParams(Method method, Class<?>... params) {
|
||||
private void register(Field field) {
|
||||
if (TRACE) {
|
||||
System.out.println(" " + field.getType() + " " + field.getName());
|
||||
}
|
||||
|
||||
RuntimeReflection.register(field);
|
||||
}
|
||||
|
||||
private void register(Method method) {
|
||||
if (TRACE) {
|
||||
System.out.println(" " + method.getReturnType().getName() + " " + method
|
||||
.getName() + "(" + params(method.getParameterTypes()) + ")");
|
||||
}
|
||||
RuntimeReflection.register(method);
|
||||
}
|
||||
|
||||
private void register(Class<?> clazz) {
|
||||
if (TRACE) {
|
||||
System.out.println("Registering " + clazz.getName() + " for reflection");
|
||||
}
|
||||
|
||||
RuntimeReflection.register(clazz);
|
||||
}
|
||||
|
||||
private static boolean hasParams(Method method, Class<?>... params) {
|
||||
Class<?>[] parameterTypes = method.getParameterTypes();
|
||||
return Arrays.equals(params, parameterTypes);
|
||||
}
|
||||
|
||||
private void registerFields(Class<?> aClass) {
|
||||
try {
|
||||
// public fields
|
||||
RuntimeReflection.register(aClass.getFields());
|
||||
} catch (NoClassDefFoundError e) {
|
||||
if (TRACE) {
|
||||
System.out.println("Public fields of "
|
||||
+ aClass.getName()
|
||||
+ " not added to reflection, as a type is not on classpath: "
|
||||
+ e.getMessage());
|
||||
}
|
||||
}
|
||||
try {
|
||||
for (Field declaredField : aClass.getDeclaredFields()) {
|
||||
// there may be fields referencing classes not on the classpath
|
||||
if (!Modifier.isPublic(declaredField.getModifiers())) {
|
||||
// public already registered
|
||||
Annotation[] annotations = declaredField.getAnnotations();
|
||||
if (annotations.length > 0) {
|
||||
RuntimeReflection.register(declaredField);
|
||||
if (TRACE) {
|
||||
System.out.println(" Annotated " + declaredField);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (NoClassDefFoundError e) {
|
||||
if (TRACE) {
|
||||
System.out.println("Fields of "
|
||||
+ aClass.getName()
|
||||
+ " not added to reflection, as a type is not on classpath: "
|
||||
+ e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void addSingleClass(BeforeAnalysisContext context,
|
||||
Class<?> theClass) {
|
||||
if (context.process(theClass)) {
|
||||
traceParsing(theClass::getName);
|
||||
traceParsing(() -> " Added for registration");
|
||||
superclasses(context, theClass);
|
||||
context.register(theClass);
|
||||
context.register(theClass).addDefaults();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -314,7 +326,7 @@ public class HelidonReflectionFeature implements Feature {
|
||||
Class<?> superclass) {
|
||||
|
||||
// this class is always registered (interface or class)
|
||||
context.register(superclass);
|
||||
context.register(superclass).addDefaults();
|
||||
|
||||
traceParsing(() -> "Looking up implementors of " + superclass.getName());
|
||||
|
||||
@@ -376,7 +388,7 @@ public class HelidonReflectionFeature implements Feature {
|
||||
traceParsing(() -> " Added for registration");
|
||||
|
||||
superclasses(context, aClass);
|
||||
context.register(aClass);
|
||||
context.register(aClass).addDefaults();
|
||||
|
||||
if (!Modifier.isFinal(modifiers)) {
|
||||
findSubclasses(context, aClass);
|
||||
@@ -397,7 +409,7 @@ public class HelidonReflectionFeature implements Feature {
|
||||
traceParsing(nextSuper::getName);
|
||||
traceParsing(() -> " Added for registration");
|
||||
|
||||
context.register(nextSuper);
|
||||
context.register(nextSuper).addDefaults();
|
||||
nextSuper = nextSuper.getSuperclass();
|
||||
}
|
||||
} else {
|
||||
@@ -491,8 +503,8 @@ public class HelidonReflectionFeature implements Feature {
|
||||
private static final class BeforeAnalysisContext {
|
||||
private final FeatureImpl.BeforeAnalysisAccessImpl access;
|
||||
private final Set<Class<?>> processed = new HashSet<>();
|
||||
private final Set<Class<?>> toRegister = new LinkedHashSet<>();
|
||||
private final Set<Class<?>> excluded = new HashSet<>();
|
||||
private final Map<Class<?>, Register> registers = new HashMap<>();
|
||||
|
||||
private BeforeAnalysisContext(BeforeAnalysisAccess access, Set<Class<?>> excluded) {
|
||||
this.access = (FeatureImpl.BeforeAnalysisAccessImpl) access;
|
||||
@@ -507,16 +519,164 @@ public class HelidonReflectionFeature implements Feature {
|
||||
return processed.add(theClass);
|
||||
}
|
||||
|
||||
public void register(Class<?> theClass) {
|
||||
this.toRegister.add(theClass);
|
||||
public Register register(Class<?> theClass) {
|
||||
return registers.computeIfAbsent(theClass, Register::new);
|
||||
}
|
||||
|
||||
public Set<Class<?>> toRegister() {
|
||||
return toRegister;
|
||||
public Collection<Register> toRegister() {
|
||||
return registers.values();
|
||||
}
|
||||
|
||||
boolean isExcluded(Class<?> theClass) {
|
||||
return excluded.contains(theClass);
|
||||
}
|
||||
}
|
||||
|
||||
private static class Register {
|
||||
private final Set<Method> methods = new HashSet<>();
|
||||
private final Set<Field> fields = new HashSet<>();
|
||||
private final Set<Constructor<?>> constructors = new HashSet<>();
|
||||
|
||||
private final Class<?> clazz;
|
||||
|
||||
private Register(Class<?> clazz) {
|
||||
this.clazz = clazz;
|
||||
}
|
||||
|
||||
boolean add(Method m) {
|
||||
return methods.add(m);
|
||||
}
|
||||
|
||||
boolean add(Field f) {
|
||||
return fields.add(f);
|
||||
}
|
||||
|
||||
boolean add(Constructor<?> c) {
|
||||
return constructors.add(c);
|
||||
}
|
||||
|
||||
void addAll() {
|
||||
addMethods();
|
||||
if (clazz.isInterface()) {
|
||||
return;
|
||||
}
|
||||
addConstructors();
|
||||
addFields(true);
|
||||
}
|
||||
|
||||
void addDefaults() {
|
||||
addMethods();
|
||||
if (clazz.isInterface()) {
|
||||
return;
|
||||
}
|
||||
addFields(false);
|
||||
addConstructors();
|
||||
}
|
||||
|
||||
private void addConstructors() {
|
||||
try {
|
||||
Constructor<?>[] constructors = clazz.getConstructors();
|
||||
for (Constructor<?> constructor : constructors) {
|
||||
add(constructor);
|
||||
}
|
||||
} catch (NoClassDefFoundError e) {
|
||||
if (TRACE) {
|
||||
System.out.println("Public constructors of "
|
||||
+ clazz.getName()
|
||||
+ " not added to reflection, as a type is not on classpath: "
|
||||
+ e.getMessage());
|
||||
}
|
||||
}
|
||||
try {
|
||||
// add all declared
|
||||
Constructor<?>[] constructors = clazz.getDeclaredConstructors();
|
||||
for (Constructor<?> constructor : constructors) {
|
||||
add(constructor);
|
||||
}
|
||||
} catch (NoClassDefFoundError e) {
|
||||
if (TRACE) {
|
||||
System.out.println("Constructors of "
|
||||
+ clazz.getName()
|
||||
+ " not added to reflection, as a type is not on classpath: "
|
||||
+ e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void addFields(boolean all) {
|
||||
Field[] fields = clazz.getFields();
|
||||
|
||||
try {
|
||||
// add all public fields
|
||||
for (Field field : fields) {
|
||||
add(field);
|
||||
}
|
||||
} catch (NoClassDefFoundError e) {
|
||||
if (TRACE) {
|
||||
System.out.println("Public fields of "
|
||||
+ clazz.getName()
|
||||
+ " not added to reflection, as a type is not on classpath: "
|
||||
+ e.getMessage());
|
||||
}
|
||||
}
|
||||
try {
|
||||
for (Field declaredField : clazz.getDeclaredFields()) {
|
||||
// there may be fields referencing classes not on the classpath
|
||||
if (!Modifier.isPublic(declaredField.getModifiers())) {
|
||||
// public already registered
|
||||
if (all || declaredField.getAnnotations().length > 0) {
|
||||
add(declaredField);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (NoClassDefFoundError e) {
|
||||
if (TRACE) {
|
||||
System.out.println("Fields of "
|
||||
+ clazz.getName()
|
||||
+ " not added to reflection, as a type is not on classpath: "
|
||||
+ e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void addMethods() {
|
||||
try {
|
||||
Method[] methods = clazz.getMethods();
|
||||
for (Method method : methods) {
|
||||
boolean register;
|
||||
|
||||
// we do not want wait, notify etc
|
||||
register = (method.getDeclaringClass() != Object.class);
|
||||
|
||||
if (register) {
|
||||
// we do not want toString(), hashCode(), equals(java.lang.Object)
|
||||
switch (method.getName()) {
|
||||
case "hashCode":
|
||||
case "toString":
|
||||
register = !hasParams(method);
|
||||
break;
|
||||
case "equals":
|
||||
register = !hasParams(method, Object.class);
|
||||
break;
|
||||
default:
|
||||
// do nothing
|
||||
}
|
||||
}
|
||||
|
||||
if (register) {
|
||||
if (TRACE) {
|
||||
System.out.println(" " + method.getName() + "(" + Arrays.toString(method.getParameterTypes()) + ")");
|
||||
}
|
||||
add(method);
|
||||
}
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
if (TRACE) {
|
||||
System.out
|
||||
.println(" Cannot register methods of " + clazz.getName() + ": " + e.getClass().getName() + ": " + e
|
||||
.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user