Pergunta

I want to make a bean which has values from properties file. I made something like this:

@Component
public class MainNavs implements Iterable<Nav>{
    @Value("${newshome.navs.names}")
    String[] names;

    @Value("${newshome.navs.ids}")
    String[] ids;

    final private List<Nav> navs = new ArrayList<Nav>();

    public MainNavs() throws Exception {            
        for (int i = 0; i < names.length; i++) {
            navs.add(new Nav(names[i], ids[i]));
        }
    }

    public Iterator<Nav> iterator() {
        Iterator<Nav> n = navs.iterator();
        return n;
    }

    public class Nav {      
        private String name;
        private String id;
        private String imageNumber;

        public Nav(String name, String id, String imageNumber) {
            this.name = name;
            this.id = id;
        }

        //....
    }
}

But when I autowire like this @Autowired MainNavs navs;, it makes NullPointerException because the names and ids were not initiated when it try to access those in constructor.

If I made some method like init() and tried to initiate with it, there wasn't any problem.

public init() throws Exception {            
    for (int i = 0; i < names.length; i++) {
        navs.add(new Nav(names[i], ids[i]));
    }
}

However, I don't want initiate manually. Can I initiate it in constructor? Or any other alternatives?

Foi útil?

Solução

Use @PostConstruct on your init() method - it will be called by spring as soon as the object is inside the spring context, which means all if its dependencies will be injected.

Outras dicas

Think about it: for spring to inject something into your bean, it needs to be created first, and it isn't created until the constructor has finished its job. You can either create the list lazily, or you can implement the spring interface InitializingBean. In your case

public class MainNavs implements Iterable<Nav>, InitializingBean {
...
public void afterPropertiesSet() throws Exception {            
    for (int i = 0; i < names.length; i++) {
        navs.add(new Nav(names[i], ids[i]));
    }
}

As a work around you could use a factory pattern, something like:

public class MainNavs implements Iterable<Nav>{

  // ...

  public init() throws Exception {            
      for (int i = 0; i < names.length; i++) {
          navs.add(new Nav(names[i], ids[i]));
      }
  }

  public static MainNavs createInstance() throws Exception {
    MainNavs result = new MainNavs();
    return result.init();
  }
}
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top