Le problème que je rencontre est le suivant: J'ai une série de classes qui sont collectées via des annotations. Ils résident tous dans le même dossier, et s'ils ont l'annotation particulière, ils sont instanciés via le Reflections
library. Pendant l'instanciation de ces classes, il existe un initialiseur statique qui appelle une fabrique statique, qui construit une structure. Java lancera l'erreur InvocationTargetException
en essayant d'obtenir l'objet créé en usine. Plus précisément, lorsque je publie la stacktrace pour ITE
, elle pointe directement sur l'initialiseur statique qui demande à l'usine l'objet.Java `InvocationTargetException` avec instanciation de classe par réflexion
Voici le code que j'utilise pour répliquer le problème.
J'ai une annotation: InferenceRule.java
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface funRule {
String ruleName();
String ruleType();
String analyze() default "node";
}
Je demande alors que l'annotation à un certain nombre de classes dans le package inference.rules
:
@InferenceRule(ruleName = "assign", ruleType = "term")
public class Assign extends NodeAnalyzer {
public Assign() {super();}
public Assign(String... args) { super(args); }
public Rule gatherAllCOnstraints(InstructionNode node) {
// use the Identifier object here.
}
// rest of class here
}
La NodeAnalyzer
classe, super de la classe Assign
ci-dessus :
public abstract class NodeAnalyzer {
protected Identifier identifier;
protected NodeAnalyzer() {
// Construct things here
}
protected NodeAnalyzer(String... args) {
// Construct other things here
}
// Construct common things here
{
this.identifier = IdentifierFactory.getIdentifier();
}
// rest of class here
}
La classe Assign
est instancié dans la classe Inference
, comme décrit ci-dessous:
public class Inference {
public final String NODE_ANALYSIS = "NODE";
public static final String INFERENCE_PACKAGE = "inference.rules";
private final Map<String, NodeAnalyzer> nodeAnalyzer = new HashMap<>();
private final Map<String, EdgeAnalyzer> edgeAnalyzer = new HashMap<>();
public Inference() {
}
// other non-interesting things here
private void loadRules() {
Reflections reflection = new Reflections(INFERENCE_PACKAGE);
Set<Class<?>> annotated = reflection.getTypesAnnotatedWith(InferenceRule.class);
for(Class<?> clazz : annotated) {
try {
String name = clazz.getAnnotation(InferenceRule.class).ruleName();
String type = clazz.getAnnotation(InferenceRule.class).ruleType();
String analyze = clazz.getAnnotation(InferenceRule.class).analyze();
if (StringUtils.equalsIgnoreCase(analyze, NODE_ANALYSIS)) {
final NodeAnalyzer newInstance = (NodeAnalyzer) clazz.getConstructor(InferenceType.class).newInstance(InferenceType.valueOf(type));
this.nodeAnalyzer.put(name, newInstance);
}
// handle other cases...
} catch(InvocationTargetException ite) {
// For debugging, only
ite.printStackTrace();
logger.error(ite.getCause.getMessage());
logger.error(ite.getTargetException.getMessage());
}
}
}
}
Comme vous pouvez le voir, à partir du chemin d'instanciation dans Assign
et NodeAnalyzer
, il doit appeler la classe IdentifierFactory
:
public class IdentifierFactory {
private static final Identifier identifier;
static {
if (ConfigFactory.getConfig().isDebEnabled()) {
identifier = new DBIdentifier();
} else {
identifier = new NaiveIdentifier();
}
}
public static Identifier getIdentifier() {
return identifier;
}
}
la classe NaiveIdentifier
:
public class NaiveIdentifier {
private Set<Integer> unknowns = new HashSet<Integer>() {{
unknowns.add(0);
// add more here.
};
public NaiveIdentifier() {} // empty default constructor
}
leLa classesuit un modèle similaire à la classe IdentifierFactory
. Il construit une config basée sur certaines entrées.
L'exception exacte jeté ressemble à:
java.lang.reflect.InvocationTargetException
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
at phases.inference.Inference.loadRules(Inference.java:197)
at phases.inference.Inference.<init>(Inference.java:76)
at phases.PhaseFacade$PHASES.getPhase(PhaseFacade.java:27)
at phases.PhaseFacade.<init>(PhaseFacade.java:42)
at compilation.Compiler.runPhases(Compiler.java:126)
at compilation.Compiler.runAllOps(Compiler.java:118)
at Main.main(Main.java:45)
Caused by: java.lang.ExceptionInInitializerError
at phases.inference.rules.NodeAnalyzer.<init>(NodeAnalyzer.java:35)
at phases.inference.rules.Assign.<init>(Assign.java:22)
... 11 more
Caused by: java.lang.NullPointerException
at typesystem.identification.NaiveIdentifier$1.<init>(NaiveIdentifier.java:23)
at typesystem.identification.NaiveIdentifier.<init>(NaiveIdentifier.java:22)
at typesystem.identification.IdentifierFactory.<clinit>(IdentifierFactory.java:25)
... 13 more
et:
java.lang.reflect.InvocationTargetException
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
at phases.inference.Inference.loadRules(Inference.java:197)
at phases.inference.Inference.<init>(Inference.java:76)
at phases.PhaseFacade$PHASES.getPhase(PhaseFacade.java:27)
at phases.PhaseFacade.<init>(PhaseFacade.java:42)
at compilation.Compiler.runPhases(Compiler.java:126)
at compilation.Compiler.runAllOps(Compiler.java:118)
at Main.main(Main.java:45)
Caused by: java.lang.NoClassDefFoundError: Could not initialize class typesystem.identification.IdentifierFactory
at phases.inference.rules.NodeAnalyzer.<init>(NodeAnalyzer.java:35)
at phases.inference.rules.Assign.<init>(Assign.java:18)
... 11 more
De ceux-ci, je ne peux pas discerner correctement ce que la cause est. Pour compliquer davantage ceci, j'ai essayé d'exécuter ceci en utilisant d'autres dossiers d'entrée et cela fonctionne très bien sur ceux-ci.
La cause racine semble être un NPE jeté dans le constructeur de la classe 'NaiveIdentifier' (ou peut-être une classe interne anonyme). Pourriez-vous s'il vous plaît modifier la question pour inclure le code de cette classe? La deuxième erreur, avec le message 'Impossible d'initialiser la classe ...' est ce qui se passe lorsque vous essayez de charger une classe qui a déjà échoué à l'initialisation statique. Java ne prend pas la peine de faire une seconde tentative pour les initialiser. –
J'ai ajouté le code pertinent. Après avoir parcouru * chaque * ligne de code, il est apparu que le problème était avec l'instanciation de 'HashSet' dans' NaiveIdentifier'. Je ne comprends pas pourquoi cela jetterait le NPE. – lilott8
L'initialisation de l'accolade double-bouclée est un anti-pattern, cachant ce qui se passe réellement dans les coulisses (créant une instance d'une classe interne sous-classant le type que vous voulez réellement instancier), le tout pour l'avantage discutable d'écrire (élément); 'au lieu de' fieldName.add (élément); '. Ironiquement, vous n'utilisez même pas cet avantage car vous avez écrit 'unknowns.add (0);', n'enregistrant aucun caractère, mais en brisant tout le code en accédant au champ 'unknowns' du constructeur de la classe interne, avant le objet construit a été affecté au champ. – Holger