JeanLucR
JeanLucR

Reputation: 1

@Autowired field returns NullPointerException (Using Neo4J)

I am making a small API using Spring Boot and Neo4J, but for some reason the @Autowired attributes to the domains are null in one of my @Service class.

The automatically generated route correctly returns the nodes from Neo4J database, so I assume there must be some error in the beans connection.

The controller:

@RestController
public class NodeController {
    @PostMapping("/metrics")
    public MetricJSON computeMetrics(
            @Valid @RequestBody MetricsPayload payload,
            @Autowired SocialNetwork socialNetwork
    ) throws InvocationTargetException, NoSuchMethodException, InstantiationException, IllegalAccessException {
        return new MetricJSON(socialNetwork.fromRequest(payload));
    }

The @Service class:

@Service
public class SocialNetwork  {
    @Autowired
    public NetworkRepository networkRepository;

    @Autowired
    public NodeRepository nodeRepository;

    @Autowired
    public Evolution evolution;

    public PersonalNetwork fromRequest(@NotNull MetricsPayload payload) throws NoSuchMethodException, InstantiationException, IllegalAccessException, InvocationTargetException {
        Network network = this.networkRepository.findById(payload.getNetworkId()).orElseThrow(NotFoundException::new);
        Node ego = this.nodeRepository.findByTag(payload.getEgoTag()).orElseThrow(NotFoundException::new);
SimpleWeightedGraph<Integer, DefaultWeightedEdge> opn = this.nodeRepository.extractOPN(ego, payload.getDepth());
        return this.fromGraph(opn, ego, payload);
}

The Node domain class:

@org.springframework.data.neo4j.core.schema.Node("Node")
public class Node {
    @Id
    private String id;
    @Property("tag")
    private String tag;
    @Relationship(type = "FROM", direction = OUTGOING)
    private Set<Node> outgoingNodes;
    @Relationship(type = "TO", direction = INCOMING)
    private Set<Node> incomingNodes;
    public String getTag() {
        return tag;
    }

    public Set<Node> getOutgoingNodes() {
        return outgoingNodes;
    }

The NodeRepository class :

public interface NodeRepository extends Neo4jRepository<Node, String> {
    Optional<Node> findByTag(String tag);
}

And yet, when I run the API I obtain this error:

Failed to complete request: java.lang.NullPointerException: Cannot invoke "com.api.repositories.NodeRepository.findByTag(String)" because "this.nodeRepository" is null

Upvotes: 0

Views: 65

Answers (2)

Roman C
Roman C

Reputation: 1

You shouldn't use @Autowired on a method parameter. It's not used by autowiring.

Marks a constructor, field, setter method or config method as to be autowired by Spring's dependency injection facilities.

Instead create a property of controller and use it in the method

@RestController
public class NodeController {

   @Autowired SocialNetwork socialNetwork;

    @PostMapping("/metrics")
    public MetricJSON computeMetrics(
            @Valid @RequestBody MetricsPayload payload
            
    ) throws InvocationTargetException, NoSuchMethodException, InstantiationException, IllegalAccessException {
        return new MetricJSON(socialNetwork.fromRequest(payload));
   }
}

Upvotes: 0

Dimitri Mestdagh
Dimitri Mestdagh

Reputation: 44745

Using the @Autowired annotation in controller methods isn't supported. You need to autowire them into the class itself. For example:

@RestController
public class NodeController {
    @Autowired
    private SocialNetwork socialNetwork; // Add this

    @PostMapping("/metrics")
    // Remove the SocialNetwork parameter from computeMetrics()
    public MetricJSON computeMetrics( 
            @Valid @RequestBody MetricsPayload payload
    ) throws InvocationTargetException, NoSuchMethodException, InstantiationException, IllegalAccessException {
        return new MetricJSON(socialNetwork.fromRequest(payload));
    }
}

(Preferably, you use construction injection in stead of field injection with @Autowired.)

The reason why you get this NullPointerException is because Spring will treat the socialNetwork parameter in your controller as a class where request attributes can be binded upon. This causes Spring to create a new instance of SocialNetwork, but not as a bean. So in this new instance of SocialNetwork, dependency injection won't happen.

Related: Why is my Spring @Autowired field null?

Upvotes: 1

Related Questions