Home > database >  NullPointerException when trying to use field-injected beans inside a @Configurable class instantiat
NullPointerException when trying to use field-injected beans inside a @Configurable class instantiat

Time:03-08

I have this enum, used in a 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;
  }
}

The idea being to be able to change what handler is used for each metadata type.

This is used in a service. Note, everything is simplified here. There are many functions that I want to be able to perform on any type of metadata without having a giant switch statement.

@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
  }
}

How do I fix this NullPointerException? It's like the enum is being processed too early and Spring never gets around to autowiring the TransactionMetadataHandler. Not sure what to do here.

CodePudding user response:

When the Enums are constructed on project startup, Spring hasn't had a chance to get up and running yet. So, instead, we can do this.

public enum MetadataType {
  TRANSACTION(TransactionMetadataHandler.class);

  private Class<? extends MetadataHandler> handlerClass;

  public MetadataHandler getHandlerClass() {
    return handlerClass;
  }

  MetadataType(Class<? extends MetadataHandler> handlerClass) {
    this.handlerClass = handlerClass;
  }
}

And then in the service, use reflection to get an instance.

@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
    }
  }
}

This way, though nothing material changes, since the instantiation of TransactionMetadataHandler is at runtime, Spring will actually be up and running, and so will field-inject properly.

CodePudding user response:

What version of java and aspectj-maven-plugin are you using ? When i follow step mentioned in https://www.baeldung.com/aspectj i got the null pointer exception , however i had to replace codehaus plugin with `

<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>

` on java version 16 and then compile team weaving worked fine for @Configurable annotation

  • Related