2

I have a JPA application that uses Spring 3. I am attempting to use @PostConstuct to iniaialise a database with specific Facility codes. When I persist a code within the Class that has the @PostConstuct method - it works. When I call a second class to persist the codes, it fails. Is this something to do with the way I am using the @Autowired annotation?

This is a segment of the Preloader class:

public class Preloader {
   @Autowired
   private FacilityService service;

   @PostConstruct
   public void init() {
      loadCodeSet();
   }

   private void loadCodeSet() {
      // This works
      Facility created = new Facility();
      created.setCode("Uni");
      created.setDescription("University");

      Facility returned = service.create(created);

      // This fails
      CodeSetLoader cl = new CodeSetLoader();
      l.load();
    }

This is a segment of the loading class:

public class CodeSetLoader {

    @Autowired
        private FacilityService facilityService;

    public void load() {
        loadFacilities();
    }

    private void loadFacilities() {
        Facility test = new Facility();
        test.setCode("UNI");
        test.setDescription("University");

        Facility returned = facilityService.create(test);
    }

The exception includes:

Caused by: java.lang.NullPointerException
    at util.CodeSetLoader.loadFacilities(CodeSetLoader.java:42)
    at util.CodeSetLoader.load(CodeSetLoader.java:24)
    at util.Preloader.loadCodeSet(Preloader.java:68)
    at util.Preloader.init(Preloader.java:32)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:601)
    at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor$LifecycleElement.invoke(InitDestroyAnnotationBeanPostProcessor.java:344)
    at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor$LifecycleMetadata.invokeInitMethods(InitDestroyAnnotationBeanPostProcessor.java:295)
    at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor.postProcessBeforeInitialization(InitDestroyAnnotationBeanPostProcessor.java:130)
    ... 22 more

Hoping somebody may be able to assist with this?

DataNucleus
  • 15,497
  • 3
  • 32
  • 37
skyman
  • 2,255
  • 4
  • 32
  • 55

4 Answers4

3

@Autowired, @PostConstruct, and friends only work on managed beans, not objects you call new on. If Spring doesn't know about the bean, it can't autowire it.

chrylis -cautiouslyoptimistic-
  • 75,269
  • 21
  • 115
  • 152
  • Thank you for this - how should I implement this then? Would I be better to use JPA without Spring or would it be better to create manages beans? – skyman Oct 14 '13 at 05:55
  • I am not sure how it would work - but maybe my PreLoader class should be a managed bean? – skyman Oct 14 '13 at 05:57
  • @bugy It depends entirely on what you're trying to do. Probably the `CodeSetLoader` class should have a Spring bean that you inject into `Preloader` (and `Preloader` needs to be a bean, too). – chrylis -cautiouslyoptimistic- Oct 14 '13 at 05:59
  • This seems to work if I inject both the Preloader bean and the CodeSetLoader bean then @Autowired works in both cases. Thank you for this - I am starting to understand how it all works :) – skyman Oct 14 '13 at 06:10
2

You need to @Autowired CodeSetLoader in your Preloader:

public class Preloader {
   @Autowired
   private FacilityService service;
   @Autowired
   CodeSetLoader codeSetLoader;

   @PostConstruct
   public void init() {
      loadCodeSet();
   }

   private void loadCodeSet() {
      // This works
      Facility created = new Facility();
      created.setCode("Uni");
      created.setDescription("University");

      Facility returned = service.create(created);

      codeSetLoader.load();
    }
}
Strelok
  • 50,229
  • 9
  • 102
  • 115
  • does this mean that Autowiring the CodeSetLoader at this point would allow @Autowired to function correctly in the CodeSetLoader class or does Spring need to be told about the CodeLoader class? – skyman Oct 14 '13 at 06:02
  • @bugy the once the component is autowired by spring, autowiring will work correctly in it. How are you defining these components? – Strelok Oct 14 '13 at 06:23
2

Autowired is called only for object created by Spring.

If possible, you should autowire CodeSetLoader instead of calling new :

public class Preloader {
   @Autowired
   private FacilityService service;

   @Autowired
   CodeSetLoader codeSetLoader;
Arnaud Denoyelle
  • 29,980
  • 16
  • 92
  • 148
1

You constructed CodeSetLoader yourself rather than letting Spring do so. As a result, facilityService never got autowired.

You need to let Spring manage both.

Vidya
  • 29,932
  • 7
  • 42
  • 70
  • Ok, I am starting to understand this. I am now telling Spring about the bean in context.xml and using @Autowired in both the PreLoader class and the CodeSetLoader class – skyman Oct 14 '13 at 06:07