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
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.
@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.
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.
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.
You can follow two approaches:
@Entity
classIf 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 @Entity
s attribute @Transient
or not, depending on your requirements).
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 @Service
s and your @Repository
s in your configuration (explicitly or by package scanning).
Using Spring MVC, you should inject (autowire) your @Service
s in a @Controller
class, so the controller can call services methods, which call DAOs methods, which access your data.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With