Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Autowired not working in a Class @Entity

I have a class called Menu, annnotated as @Entity where i need to use a method inside a class called GestoreMessaggi

....    
@Component
@Entity
@Table(name="menu")
public class Menu implements Serializable{

@Autowired
@Transient // because i dont' save this field on the DB
private GestoreMessaggi gestoreMessaggi;
.....
public void setCurrentLanguage(){

   /* I got the error both if use gestoreMessaggi
   this way and if I use the autowired istance of GestoreMessaggi*/
   GestoreMessaggi gestoreMessaggi = new GestoreMessaggi();  
   gestoreMessaggi.gest();        
}
.....

This is the relevant code of the class GestoreMessaggi

 @Component
    public class GestoreMessaggi {    
        @Autowired 
        private ReloadableResourceBundleMessageSource messageSource;

        public void gest(){
        messageSource.doSomething() <--- here messageSource is null
        }
  }

When, I call gestoreMessaggi.gest(); from Menu class, I got an error because messageSource is null. The gestoreMessaggi istance is NOT null, is null just messageSource

IMPORTANT: I get null on messageSource only when I call GestoreMessaggi from classes annotated as @Entity.

In ds-servlet.xml I tell Spring to scan the pakages that contain Menu and GestoreMessaggi classes:

//Menu package 
<context:component-scan base-package="com.springgestioneerrori.model"/>
//Gestore messaggi package
<context:component-scan base-package="com.springgestioneerrori.internazionalizzazione"/>   

Thank you

like image 208
MDP Avatar asked Feb 06 '15 11:02

MDP


People also ask

Why is my Autowired not working?

When @Autowired doesn't work. There are several reasons @Autowired might not work. When a new instance is created not by Spring but by for example manually calling a constructor, the instance of the class will not be registered in the Spring context and thus not available for dependency injection.

Can we use @autowired in a class?

@Autowired annotation can be applied on variables and methods for autowiring byType. We can also use @Autowired annotation on constructor for constructor based spring autowiring. For @Autowired annotation to work, we also need to enable annotation based configuration in spring bean configuration file.

Can we use @autowired in pojo?

The beans can be wired via constructor or properties or setter method. For example, there are two POJO classes Customer and Person. The Customer class has a dependency on the Person. @Autowired annotation is optional for constructor based injection.

Is @component required for Autowired?

Injection and autowiring do not require @Component . They require beans. @Component states that the annotated type should have a bean generated for it. You can define beans in other ways: with a <bean> declaration in an XML context configuration, with a @Bean method in a @Configuration class, etc.


2 Answers

You can follow two approaches:

  1. Try to get an instance of a Spring-managed bean from within a method of your @Entity class
  2. Change the design as suggested by @Stijn Geukens and make your entity a POJO without any logic or dependency injection machanisms

If you go by option 1, you have to explicitly access Spring's context and retrieve an instance of the bean you need:

@Component
public class Spring implements ApplicationContextAware {

    private static final String ERR_MSG = "Spring utility class not initialized";

    private static ApplicationContext context;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        context = applicationContext;   
    }

    public static <T> T bean(Class<T> clazz) {
        if (context == null) {
            throw new IllegalStateException(ERR_MSG);
        }
        return context.getBean(clazz);
    }

    public static <T> T bean(String name) {
        if (context == null) {
            throw new IllegalStateException(ERR_MSG);
        }
        return (T) context.getBean(name);
    }
}

You need to make Spring scan this class in order for this to work.

Then, inside your @EntityClass, do this:

public void setCurrentLanguage(){
    GestoreMessaggi gestoreMessaggi = Spring.bean(GestoreMessaggi.class);
    gestoreMessaggi.gest();        
}

And that would be all. Note that you wouldn't need to autowire GestoreMessaggi into your @Entity any more. Please also note that this approach is not recommended neither by Spring nor by most of the community, since it couples your domain classes (your @Entity class) to Spring classes.

If you go by option 2, then all you need to do is let Spring resolve the autowiring as usual, but outside of your entity (i.e. in a dao or service), and if your entity needs you to fill it with some message or whatever, just invoke a setter on it. (Then it's up to you to make your @Entitys attribute @Transient or not, depending on your requirements).

like image 166
fps Avatar answered Nov 05 '22 20:11

fps


Spring context does not manage entities (in general does not manage objects instantiated using new), this is why you cannot autowire beans (that come from Spring's context) in entities.

Best practices suggest to keep only getter and setter in your entities, leaving the business logic to the service layer.

A common approach is Service <-> DAO <-> Entity. Example:

Service layer:

@Service
public interface GestoreMessaggi {
    public void gest();
}

public class GestoreMessaggiImpl implements GestoreMessaggi {

    @Autowired
    private MenuDao menuDao;

    @Override
    public void gest() {
        // 1) retrieve your entity instance with menuDao
        // 2) do stuffs with your entity
        // 3) maybe save your entity using menuDao
    }
}

DAO layer:

If you use Spring Data Jpa:

public interface MenuDao extends JpaRepository<Menu, [menu-id-type]> {}

Else:

public interface MenuDao {
    public Menu findOne([menu-id-type] id);
    public Menu save(Menu menu);
    // other methods for accessing your data
}

@Repository
public class MenuDaoImpl {
    // inject EntityManager or Hibernate SessionFactory
    // implement your DAO interface accessing your entities
}

Finally remember to configure Spring's beans including your @Services and your @Repositorys in your configuration (explicitly or by package scanning).

Using Spring MVC, you should inject (autowire) your @Services in a @Controller class, so the controller can call services methods, which call DAOs methods, which access your data.

like image 30
Francesco Pitzalis Avatar answered Nov 05 '22 20:11

Francesco Pitzalis