Searene
Searene

Reputation: 27574

Access both runtime argument and other beans in a spring bean's constructor

I have two beans in a spring-boot application:

@Component
@Scope(BeanDefinition.SCOPE_PROTOTYPE)
public class Shape {

    @Resource
    private ShapeService shapeService;

    private String name;
    private String description;

    public Shape(String name) {
        this.name = name;
        this.description = shapeService.getDescription();
    }
}
@Service
public class ShapeService {

    public String getDescription() {
        return "This is a shape.";
    }
}

I created the Shape instance using the following code:

Shape shape = beanFactory.getBean(Shape.class, "shape");

But I got a NullPointerException on the following line:

this.description = shapeService.getDescription();

shapeService is null. Is there any way to use shapeService inside Shape's constructor?

Upvotes: 0

Views: 172

Answers (1)

CryptoFool
CryptoFool

Reputation: 23089

The problem is that Spring has to create an object before it can do field injection on it. So the field you are referencing hasn't been set yet by Spring, but will be later on, after the object is fully constructed. If that line were in a regular method, it would work.

To fix this, you have to have Spring pass the reference to your ShapeService to your constructor via a constructor argument. Change your code for your Shape class to look like this:

@Component
@Scope(BeanDefinition.SCOPE_PROTOTYPE)
public class Shape {

    private ShapeService shapeService;

    private String name;
    private String description;

    public Shape(String name, ShapeService shapeService) {
        this.name = name;
        this.shapeService = shapeService;
        this.description = shapeService.getDescription();
    }
}

I prefer constructor argument injection over autowiring even if it isn't necessary, like it is in your case. Constructor injection is generally considered to be better form. Here's an article that explains why

Upvotes: 1

Related Questions