Spring - @Autowire a List with elements

Asked

Viewed 418 times

1

I have a controller that has this @Autowired:

@Autowired
Rules rules;

This Rules class is defined as follows::

@Service
public class Rules {

    @Autowired
    private List<RegistrationRule> allRules;

    public List<RegistrationRule> getAllRules() {
        return allRules;
    }
}

I want when doing the @Autowired in the list allRules it already comes with some standard items within it, as follows:

allRules.add( new EmployeePositionRule() );
allRules.add( new CostCenterRule() );

I tried to put in the Rules class builder in the following way:

public Rules() {
    allRules.add( new EmployeePositionRule() );
    allRules.add( new CostCenterRule() );
}

But if I do so an exception is released at the time of compiling the project:

org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'intRaptMecController': Unsatisfied dependency expressed through field 'rules'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'rules' defined in file [...validations\rules\Rules.class]: Instantiation of bean failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [validations.rules.Rules]: Constructor threw exception; nested exception is java.lang.NullPointerException

What’s the right way to do it?

  • UnsatisfiedDependencyException means that Spring doesn’t know where a dependency comes from that needs to be injected. In his case, he doesn’t know how to inject a List<RegistrationRule> in your class Rules.

2 answers

3

The reason is simple.

The builder of the class Rules is called before to inject the List<RegistrationRule> in the field allRules. Therefore, allRules will always be null.

This would be the current code, still with the problem:

@Service
public class Rules {

    @Autowired
    private List<RegistrationRule> allRules;

    public Rules() {
       allRules.add( new EmployeePositionRule() ); //allRules estará nulo!
       allRules.add( new CostCenterRule() );
    }

    public List<RegistrationRule> getAllRules() {
        return allRules;
    }
}

The correction may be to injection by manufacturer or by method set. In fact, avoid using @Autowired in private fields (the famous Field Injection), because this injection technique is the least recommended by several reasons, although it is (unfortunately) very common.

So try doing it this way:

@Service
public class Rules {

    private List<RegistrationRule> allRules;

    @Autowired
    public Rules(List<RegistrationRule> allRules) {
       allRules.add( new EmployeePositionRule() );
       allRules.add( new CostCenterRule() );
    }

    public List<RegistrationRule> getAllRules() {
        return allRules;
    }
}

Also confirm that your @Bean list of RegistrationRule was created correctly. It can be created within any class annotated with @Configuration (org.springframework.context.annotation.Configuration), in this way:

@Configuration
public class RulesConfiguration {

    @Bean
    public List<RegistrationRule> allRules() {
       List<RegistrationRule> rules = new ArrayList();
       return rules;
    }

}
  • I did it the way you said it. However, the list allRules does not create an instance, getting "null" and launching a Nullpointerexception when I try to traverse it using the line for(Registrationrule Rule : Rules.getAllRules())

  • @Witnesstruth, show in your question how you created the Bean of List<RegistrationRule>. Wellington’s response shows a way to do this and make sure that it will not come void. I assumed that the creation of this List was correct in my answer. It is likely that my answer and his will solve your problem.

  • @Witnesstruth, see an example of the creation of allRules as Bean can be injected.

  • Hello! I had to return the question because I put it exactly the way you sent me the code. However, as I added other Rules, instead of just taking the Rules I put inside the constructor, it takes all the Rules that are inside the package. I don’t understand why this is happening

  • Hello! What do you mean? Which package? If I understand what you mean, you are adding new Ules into the constructor and they are being added to the list and passed to other classes?

  • In my project I have a package called "Rules" and in it is the class Rules (@Service) with the same code you gave me, a Registrationrule interface with 1 validated method (Pointing pointing) and other 7 which are classes that "Implements" that interface (Registrationrule).

  • Only in the constructor I put so that only 3 of these 7 classes were in the list. But still it is adding all 7.

  • You are added these other 4 in some other class, correct @Witnesstruth?

  • I’m not. The only thing I did with this Rules class was to give an @Autowired in a Controller and use a Loop in the list that the getAllRules() method returns.

  • 1

    @Witnesstruth, I recommend creating a new question to show the details of the implementation. I understand that this is a new problem.

Show 5 more comments

2


As Leonardo Lima commented, the UnsatisfiedDependencyException happens because Spring didn’t find any Bean of the kind List<RegistrationRule>. For this, you can declare a method that returns the default values you need. Example:

@Bean
public List<RegistrationRule> myDefaultRules() {
  List<RegistrationRule> defaultRules = new ArrayList();
  defaultRules.add(new EmployeePositionRule());
  defaultRules.add(new CostCenterRule());
  return defaultRules;
}

Reappoint that the annotation @Bean serves to tell Spring that you are providing a dependency, in case your default list of RegistrationRule.

In case you wanted different values to be injected into your list allRules, you will need to declare other Beans and use the annotation @Qualifier to differentiate between which list of RegistrationRule you want to inject. Example:

@Bean(name = "defaultRules")
public List<RegistrationRule> myDefaultRules() {
  List<RegistrationRule> defaultRules = new ArrayList();
  defaultRules.add(new EmployeePositionRule());
  defaultRules.add(new CostCenterRule());
 return defaultRules;
}

@Bean(name = "otherRules")
public List<RegistrationRule> otherRules() {
  List<RegistrationRule> otherRules = new ArrayList();
  otherRules.add(new FooRule());
  otherRules.add(new MyOtherRule());
  return otherRules;
}

@Autowired
@Qualifier("defaultRules")
private List<RegistrationRule> defaultRules;

@Autowired
@Qualifier("otherRules")
private List<RegistrationRule> otherRules;

I hope I’ve helped!

EDIT 1:

Try this example.

@Configuration
public class RulesConfiguration {

    @Bean
    public List<RegistrationRule> allRules() {
        List<RegistrationRule> allRules = new ArrayList();
        allRules.add(new EmployeePositionRule());
        allRules.add(new CostCenterRule());
        return allRules;
    }

}

@Service
public class RuleService {

    @Autowired
    List<RegistrationRule> rules;

}
  • But where should I put this code? Inside the Rules class? Or in my Controller? I put it inside the Rules class but it’s firing the same exception :(

  • Test whether the answer EDIT 1 code works for you.

  • @Witnesstruth, you need to create this @Bean within a class marked with @Configuration.

  • Well noted @Dherik. I edited the answer.

  • The detail of your Qualifier did what I wanted and still solved a problem I had later when adding other rules. With this Qualifier will be good to solve other things we can face here. Thank you

Browser other questions tagged

You are not signed in. Login or sign up in order to post.