尝试在枚举中实例化的 @Configurable class 中使用字段注入的 bean 时出现 NullPointerException?
NullPointerException when trying to use field-injected beans inside a @Configurable class instantiated in an enum?
我有这个枚举,用在 dto 中。
public enum MetadataType {
TRANSACTION(new TransactionMetadataHandler());
private MetadataHandler handler;
public MetadataHandler getHandler() {
return handler;
}
MetadataType(MetadataHandler handler) {
this.handler = handler;
}
}
public class MetadataInfo {
private MetadataType type;
public MetadataType getType() {
return this.type;
}
}
想法是能够更改用于每种元数据类型的处理程序。
这是在服务中使用的。注意,这里的一切都被简化了。我希望能够在没有巨大的 switch 语句的情况下对任何类型的元数据执行许多功能。
@Service
public class MetadataService {
public String formatMetadata(MetadataInfo info) {
String formattedMetadata = info.getType().getHandler().format(info);
return formattedMetadata;
}
}
public interface MetadataHandler {
String formatMetadata(MetadataInfo info);
}
@Configurable
public class TransactionMetadataHandler implements MetadataHandler {
@Autowired
private SomeOtherBean someOtherBean;
public String formatMetadata(MetadataInfo info) {
someOtherBean.doSomething(); // NullPointerException here
}
}
如何修复此 NullPointerException?这就像枚举被处理得太早了,Spring 永远不会自动装配 TransactionMetadataHandler
。不知道在这里做什么。
在项目启动时构建枚举时,Spring 还没有机会起床,运行 还没有。所以,相反,我们可以这样做。
public enum MetadataType {
TRANSACTION(TransactionMetadataHandler.class);
private Class<? extends MetadataHandler> handlerClass;
public MetadataHandler getHandlerClass() {
return handlerClass;
}
MetadataType(Class<? extends MetadataHandler> handlerClass) {
this.handlerClass = handlerClass;
}
}
然后在服务中,使用反射获取实例。
@Service
public class MetadataService {
public String formatMetadata(MetadataInfo info) {
try {
String formattedMetadata = info.getType().getHandlerClass().newInstance().format(info);
return formattedMetadata;
} catch (InstantiationException | IllegalAccessException e) {
// do whatever with the exception
}
}
}
这样,尽管 material 没有任何变化,但由于 TransactionMetadataHandler
的实例化是在运行时进行的,因此 Spring 实际上会启动,运行 也会启动 field-inject 正确。
您使用的 java 和 aspectj-maven-plugin 是什么版本?当我按照 https://www.baeldung.com/aspectj 中提到的步骤进行时,我得到了空指针异常,但是我不得不用 `
替换 codehaus 插件
<plugins>
<plugin>
<groupId>dev.aspectj</groupId>
<artifactId>aspectj-maven-plugin</artifactId>
<version>1.13.M3</version>
<configuration>
<complianceLevel>16</complianceLevel>
<aspectLibraries>
<aspectLibrary>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
</aspectLibrary>
</aspectLibraries>
</configuration>
<executions>
<execution>
<goals>
<goal>compile</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
` 在 java 版本 16 上,然后编译团队编织对 @Configurable 注释工作正常
我有这个枚举,用在 dto 中。
public enum MetadataType {
TRANSACTION(new TransactionMetadataHandler());
private MetadataHandler handler;
public MetadataHandler getHandler() {
return handler;
}
MetadataType(MetadataHandler handler) {
this.handler = handler;
}
}
public class MetadataInfo {
private MetadataType type;
public MetadataType getType() {
return this.type;
}
}
想法是能够更改用于每种元数据类型的处理程序。
这是在服务中使用的。注意,这里的一切都被简化了。我希望能够在没有巨大的 switch 语句的情况下对任何类型的元数据执行许多功能。
@Service
public class MetadataService {
public String formatMetadata(MetadataInfo info) {
String formattedMetadata = info.getType().getHandler().format(info);
return formattedMetadata;
}
}
public interface MetadataHandler {
String formatMetadata(MetadataInfo info);
}
@Configurable
public class TransactionMetadataHandler implements MetadataHandler {
@Autowired
private SomeOtherBean someOtherBean;
public String formatMetadata(MetadataInfo info) {
someOtherBean.doSomething(); // NullPointerException here
}
}
如何修复此 NullPointerException?这就像枚举被处理得太早了,Spring 永远不会自动装配 TransactionMetadataHandler
。不知道在这里做什么。
在项目启动时构建枚举时,Spring 还没有机会起床,运行 还没有。所以,相反,我们可以这样做。
public enum MetadataType {
TRANSACTION(TransactionMetadataHandler.class);
private Class<? extends MetadataHandler> handlerClass;
public MetadataHandler getHandlerClass() {
return handlerClass;
}
MetadataType(Class<? extends MetadataHandler> handlerClass) {
this.handlerClass = handlerClass;
}
}
然后在服务中,使用反射获取实例。
@Service
public class MetadataService {
public String formatMetadata(MetadataInfo info) {
try {
String formattedMetadata = info.getType().getHandlerClass().newInstance().format(info);
return formattedMetadata;
} catch (InstantiationException | IllegalAccessException e) {
// do whatever with the exception
}
}
}
这样,尽管 material 没有任何变化,但由于 TransactionMetadataHandler
的实例化是在运行时进行的,因此 Spring 实际上会启动,运行 也会启动 field-inject 正确。
您使用的 java 和 aspectj-maven-plugin 是什么版本?当我按照 https://www.baeldung.com/aspectj 中提到的步骤进行时,我得到了空指针异常,但是我不得不用 `
替换 codehaus 插件<plugins>
<plugin>
<groupId>dev.aspectj</groupId>
<artifactId>aspectj-maven-plugin</artifactId>
<version>1.13.M3</version>
<configuration>
<complianceLevel>16</complianceLevel>
<aspectLibraries>
<aspectLibrary>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
</aspectLibrary>
</aspectLibraries>
</configuration>
<executions>
<execution>
<goals>
<goal>compile</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
` 在 java 版本 16 上,然后编译团队编织对 @Configurable 注释工作正常