when I have injected the been AdminService the java.lang.NullPointerException appeared , although I inject this bean with the same way in another managed bean and everything works :
#ManagedBean
#SessionScoped
public class ScheduleController implements Serializable {
/**
*
*/
private static final long serialVersionUID = -1489523494215832724L;
private ScheduleModel eventModel;
#ManagedProperty(value = "#{adminService}")
AdminService adminService;
private ScheduleEvent event = new DefaultScheduleEvent();
public ScheduleController() {
List<Service> = adminService.getAllService();
}
public AdminService getAdminService() {
return adminService;
}
public void setAdminService(AdminService adminService) {
this.adminService = adminService;
}
AdminService implementation:
Service("adminService")
public class AdminServiceImpl implements AdminService,Serializable {
/**
*
*/
private static final long serialVersionUID = 1L;
#Autowired
AdminDao adminDao ;
// adminDao injected by spring
#Transactional
public void add(Admin admin) {
adminDao.save(admin);
}
#Transactional
public void edit(Admin admin) {
adminDao.update(admin);
}
#Transactional
public void delete(Admin admin) {
adminDao.delete(admin);
}
#Transactional
public Admin getAdmin(Integer adminId) {
return adminDao.findById(adminId);
}
#Transactional
public List<Admin> getAllAdmin() {
return adminDao.findAll();
}
/**
* #return the adminDao
*/
public AdminDao getAdminDao() {
return adminDao;
}
/**
* #param adminDao the adminDao to set
*/
public void setAdminDao(AdminDao adminDao) {
this.adminDao = adminDao;
}
#Override
public Admin authenticate(String adminName, String adminPass) {
return this.adminDao.authenticate(adminName, adminPass);
}
}
You're trying to access the injected dependency during construction of the bean. This is obviously not going to work. You're basically expecting that it all works like follows under the covers:
ScheduleController scheduleController; // Declare.
scheduleController.adminService = new AdminService(); // Inject.
scheduleController = new ScheduleController(); // Construct.
This makes no sense. It's not possible to set an instance variable before the instance is constructed. Instead, it works like follows:
ScheduleController scheduleController; // Declare.
scheduleController = new ScheduleController(); // Construct.
scheduleController.adminService = new AdminService(); // Inject.
If you'd like to perform an action directly after construction and injection, then you should be using a #PostConstruct annotated method.
So, replace
public ScheduleController() {
List<Service> services = adminService.getAllService();
}
by
#PostConstruct
public void init() { // Note: method name is fully free to your choice.
List<Service> services = adminService.getAllService();
}
No need for the <f:event> mess. It also doesn't necessarily need to go in <f:metadata> by the way.
i find the solution , the problem is not a problem of injection is a problem of call, I worked with this ways, and it works :
in the managed bean i add a init method :
public void init(){
List<Service> = adminService.getAllService();
}
and in the page.xhtml :
<f:metadata>
<f:event type="preRenderView" listener="#{scheduleController.init()}"/>
</f:metadata>
Related
I am following this article to implement a database read/write separation feature by calling different methods. However, I got the error:
Missing method call for verify(mock) here: verify(spyDatabaseContextHolder, times(1)).set(DatabaseEnvironment.READONLY);
when doing the testing.
My test case is trying to verify DatabaseEnvironment.READONLY has been set once when using TransactionReadonlyAspect AOP annotation:
// TransactionReadonlyAspectTest.java
#RunWith(SpringRunner.class)
#ContextConfiguration(classes = {LoadServiceImpl.class, TransactionReadonlyAspect.class})
public class TransactionReadonlyAspectTest {
#Autowired
private TransactionReadonlyAspect transactionReadonlyAspect;
#MockBean
private LoadServiceImpl loadService;
#Test
public void testReadOnlyTransaction() throws Throwable {
ProceedingJoinPoint mockProceedingJoinPoint = mock(ProceedingJoinPoint.class);
Transactional mockTransactional = mock(Transactional.class);
DatabaseContextHolder spyDatabaseContextHolder = mock(DatabaseContextHolder.class);
when(mockTransactional.readOnly()).thenReturn(true);
when(loadService.findById(16)).thenReturn(null);
when(mockProceedingJoinPoint.proceed()).thenAnswer(invocation -> loadService.findById(16));
transactionReadonlyAspect.proceed(mockProceedingJoinPoint, mockTransactional);
verify(spyDatabaseContextHolder, times(1)).set(DatabaseEnvironment.READONLY); // got the error: Missing method call for verify(mock)
verify(loadService, times(1)).findById(16);
assertEquals(DatabaseContextHolder.getEnvironment(), DatabaseEnvironment.UPDATABLE);
}
}
//TransactionReadonlyAspect.java
#Aspect
#Component
#Order(0)
#Slf4j
public class TransactionReadonlyAspect {
#Around("#annotation(transactional)")
public Object proceed(ProceedingJoinPoint proceedingJoinPoint,
org.springframework.transaction.annotation.Transactional transactional) throws Throwable {
try {
if (transactional.readOnly()) {
log.info("Inside method " + proceedingJoinPoint.getSignature());
DatabaseContextHolder.set(DatabaseEnvironment.READONLY);
}
return proceedingJoinPoint.proceed();
} finally {
DatabaseContextHolder.reset();
}
}
}
// DatabaseContextHolder.java
public class DatabaseContextHolder {
private static final ThreadLocal<DatabaseEnvironment> CONTEXT = new ThreadLocal<>();
public static void set(DatabaseEnvironment databaseEnvironment) {
CONTEXT.set(databaseEnvironment);
}
public static DatabaseEnvironment getEnvironment() {
DatabaseEnvironment context = CONTEXT.get();
System.out.println("context: " + context);
return CONTEXT.get();
}
public static void reset() {
CONTEXT.set(DatabaseEnvironment.UPDATABLE);
}
}
//DatabaseEnvironment.java
public enum DatabaseEnvironment {
UPDATABLE,READONLY
}
// LoadServiceImpl.java
#Service
public class LoadServiceImpl implements LoadService {
#Override
#Transactional(readOnly = true)
public LoadEntity findById(Integer Id) {
return this.loadDAO.findById(Id);
}
...
}
I just want to test DatabaseContextHolder.set(DatabaseEnvironment.READONLY) has been used once then in the TransactionReadonlyAspect finally block it will be reset to DatabaseEnvironment.UPDATABLE which make sense.
However, how to test DatabaseContextHolder.set(DatabaseEnvironment.READONLY) gets called once? Why does this error occur? Is there a better way to test TransactionReadonlyAspect?
I try to implement chain of responsibility with quarkus 2.10.0.
I have class IssueChangeChain and no one IssueChangeChainLink doesn't inject in field links.
#ApplicationScoped
public class IssueChangeChain {
#Inject
#All
List<IssueChangeChainLink> links;
public void processIssueChange(JiraChangeDTO change) {
logger.info("Try to process " + change + " through " + links);
if(change == null)
return;
links.forEach(link ->{
var changeItem = link.getChangeItem(change);
if (changeItem != null) {
link.processChangeItem(changeItem);
}
});
}
void setLinks(List<IssueChangeChainLink> links) {
this.links = links;
}
}
And three classes implemented IssueChangeChainLink
#ApplicationScoped
public class IssueCreationChainLink implements IssueChangeChainLink<AddJiraIssueDTO> {
#Override
public AddJiraIssueDTO getChangeItem(JiraChangeDTO change) {
...
}
#Override
public void processChangeItem(AddJiraIssueDTO changeItem) {
...
}
private static final Logger log = LoggerFactory.getLogger(IssueCreationChainLink.class);
}
#ApplicationScoped
public class SprintChangeChainLink implements IssueChangeChainLink<IssueAddSprintDTO> {
#Override
public IssueAddSprintDTO getChangeItem(JiraChangeDTO change) {
...
}
#Override
public void processChangeItem(IssueAddSprintDTO changeItem) {
...
}
private static final Logger log = LoggerFactory.getLogger(SprintChangeChainLink.class);
}
What should I do to inject List of beans?
#Inject
List<?> instances;
does not work in Quarkus as this is not supported in CDI. In CDI it is looking for a bean which is a List.
What you should do is inject
#Inject
#All
Instance<IssueChangeChainLink> instances;
Instance from CDI implements Iterable, which you can then use .stream() or .forEach() from to iterate over beans.
I am trying to create a Spring boot application with JFrame. I can see my beans in applicationContext but they are not getting autowired. I am unable to find the reason for this issue. Can someone help me with this?
Here is the code:
JavauiApplication - it is showing both userManager and userNameRepository is beans
#SpringBootApplication
public class JavauiApplication implements CommandLineRunner {
#Autowired
private ApplicationContext appContext;
public static void main(String[] args) {
new SpringApplicationBuilder(JavauiApplication.class).headless(false).run(args);
java.awt.EventQueue.invokeLater(() -> new InputNameForm().setVisible(true));
}
#Override
public void run(String... args) throws Exception {
String[] beans = appContext.getBeanDefinitionNames();
Arrays.sort(beans);
for (String bean : beans) {
System.out.println(bean);
}
}
}
InputNameForm.java -> userManager coming null
#Component
public class InputNameForm extends javax.swing.JFrame {
/**
* Creates new form InputNameForm
*/
public InputNameForm() {
initComponents();
}
#Autowired
UserManager userManager;
private void submitButtonActionPerformed(java.awt.event.ActionEvent evt) {
userManager.setName(firstName.getText(), lastName.getText());
}
/**
* #param args the command line arguments
*/
public static void main(String args[]) {
try {
for (javax.swing.UIManager.LookAndFeelInfo info : javax.swing.UIManager.getInstalledLookAndFeels()) {
if ("Nimbus".equals(info.getName())) {
javax.swing.UIManager.setLookAndFeel(info.getClassName());
break;
}
}
} catch (ClassNotFoundException ex) {
java.util.logging.Logger.getLogger(InputNameForm.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
}
/* Create and display the form */
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
new InputNameForm().setVisible(true);
}
});
}
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JTextField firstName;
private javax.swing.JLabel firstNameLabel;
private javax.swing.JTextField lastName;
private javax.swing.JLabel lastNameLabel;
private javax.swing.JButton submitButton;
// End of variables declaration//GEN-END:variables
}
UserManager.java -> userNameRepository is coming null
#Component
public class UserManager {
#Autowired
UserNameRepository userNameRepository;
public void setName(String firstName, String lastName) {
userNameRepository.save(new UserName(firstName, lastName));
System.out.println(userNameRepository.findAllByFirstName(firstName));
}
}
It's a very common problem and it occurs because newcomers don't understand how the IoC container works.
Firstly, BeanDefinitionReader reads metadata about your beans from XML, Annotations(#Component, #Service etc), JavaConfig or Groovy script.
There are several BeanPostProcessor's which is responsible for reading all of these Spring annotation you're writing(#Autowired etc).
BeanFactory creates all BeanPostProcessor's then it creates all of your beans.
What happen if you create your bean with #Autowired dependencies via new operator? Nothing, because it isn't actually a bean. The object you created isn't related to IoC container. You may have the bean already in your ApplicationContext if you marked it with #Component(for example) but the object which was created via new operator wont be processed by Spring(annotations won't work).
Hope this helps.
PS: The lifecycle is simplified.
I had the same problem few days ago. What I undertood was that GUI builders like the one that comes with netbeans will automatically create components using new keyword. This means that those components won't be manage by spring. The code usually loks like this:
private void initComponents() {
jPanel1 = new javax.swing.JPanel(); //This component will not be managed by spring.
//...
}
You could use the following class provided here, to make it work.
#Component
public class BeanProvider {
private static ApplicationContext applicationContext;
// Autowires the specified object in the spring context
public static void autowire(Object object) {
applicationContext.getAutowireCapableBeanFactory().autowireBean(object);
}
#Autowired
private void setApplicationContext(ApplicationContext applicationContext) {
BeanProvider.applicationContext = applicationContext;
}
}
The top level SwingApp class:
#SpringBootApplication
public class SwingApp implements CommandLineRunner {
public static void main(String[] args) {
new SpringApplicationBuilder(SwingApp.class)
.headless(false).bannerMode(Banner.Mode.OFF).run(args);
}
#Override
public void run(String... args) throws Exception {
SwingUtilities.invokeLater(() -> {
MainFrame frame = new MainFrame();
frame.setVisible(true);
});
}
}
The MainFrame class:
public class MainFrame extends javax.swing.JFrame {
public MainFrame() {
initComponents();
}
private void initComponents() {
//Gui Builder generated code. Bean not managed by spring.
//Thus, autowired inside CustomPanel won't work if you rely on ComponentScan.
jPanel1 = new CustomJPanel();
//...
}
private CustomJPanel jPanel1;
}
The panel class where you want to autowire things:
//#Component //not needed since it wont work with gui generated code.
public class CustomJPanel extends javax.swing.JPanel{
#Autowired
private SomeRepository someRepository
public CustomJPanel(){
BeanProvider.autowire(this); //use someRepository somewhere after this line.
}
}
I have the same problem in a JavaFx project. Service and Component annotated classes were null in UI controllers even if it was shown in context that it was created. Below code worked for me
#Component
public class FxmlLoaderWithContext {
private final ApplicationContext context;
#Autowired
public FxmlLoaderWithContext(ApplicationContext context) {
this.context = context;
FXMLLoader fxmlloader = new FXMLLoader();
fxmlloader.setControllerFactory(context::getBean); //this row ensure services and components to be autowired
}
}
I think it returns null because you using command new to create object, such as new InputNameForm(). When creating object like that, the object isn't managed by Spring. That's why autowired not working.
The solution is registering your class as a bean.
You can use a class like in here.
#Component
public class BeanProvider {
private static ApplicationContext applicationContext;
public static void autowire(Object object) {
applicationContext.getAutowireCapableBeanFactory().autowireBean(object);
}
#Autowired
private void setApplicationContext(ApplicationContext applicationContext) {
BeanProvider.applicationContext = applicationContext;
}
}
And then, in your class InputNameForm constructor, call this:
class InputNameForm() {
BeanProvider.autowire(this);
...
}
And that's it. Spring will take care the rest.
I have following spring bean with Prototype scope. In the AppRunner class, I want a new bean to injected by spring within the for loop (if loop count is 2, then i want only 2 new beans to be injected).
But spring injects a new bean every time the setter methods of the SimpleBean is called.
SimpleBean.java
#Component
#Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE, proxyMode =
ScopedProxyMode.TARGET_CLASS)
public class SimpleBean {
private String id;
private Long value;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public Long getValue() {
return value;
}
public void setValue(Long value) {
this.value = value;
}
}
AppRunner.java
#Component
public class AppRunner {
#Autowired
SimpleBean simpleBean;
public void execute(List<Output> results){
List<SimpleBean> finalResults = new ArrayList<SimpleBean>();
for(Output o : results){
simpleBean.setId(o.getAppId());
simpleBean.setValue(o.getAppVal());
finalResults.add(simpleBean);
}
}
}
Output.java
public class Output {
private String appId;
private Long appVal;
public String getAppId() {
return appId;
}
public void setAppId(String appId) {
this.appId = appId;
}
public Long getAppVal() {
return appVal;
}
public void setAppVal(Long appVal) {
this.appVal = appVal;
}
}
Unfortunately prototype scope doesn't work like this. When your AppRunner bean is instantiated by the container it is asking for its dependencies. Then a new instance of SimpleBean is created. This instance stays as dependency. Prototype scope starts working when you will have multiple beans with dependency on SimpleBean. Like:
#Component
class BeanOne {
#Autowired
SimpleBean bean; //will have its own instance
}
#Component
class BeanTwo {
#Autowired
SimpleBean bean; //another instance
}
There is one rather straightforward update which can lead to your desired behaviour. You can remove autowired dependency and ask for a new dependency in your loop from context. It would look like this.
#Component
public class AppRunner {
#Autowired
ApplicationContext context;
public void execute(List<Output> results){
List<SimpleBean> finalResults = new ArrayList<SimpleBean>();
for(Output o : results) {
SimpleBean simpleBean = context.getBean(SimpleBean.class);
simpleBean.setId(o.getAppId());
simpleBean.setValue(o.getAppVal());
finalResults.add(simpleBean);
}
}
}
Other option could be technique called Method injection. It is described in the relevant documentation for prototype scope. You can take a look here 7.5.3 Singleton beans with prototype-bean dependencies
I was trying to use spring's eventLisnter in spring-boot 1.3.5.RELEASE.
I was wondering if there is a standard way to return saved object back, or return more information after event was processed.
I may use event as a container to set my saved object back, but I am not sure if this is the best practice, any advice will be appreciated:)
Here is the example:
public class StoreOrderEvent extends ApplicationEvent {
private OrderBean orderBean;
/**
* Create a new ApplicationEvent.
*
* #param source the object on which the event initially occurred (never {#code null})
*/
public StoreOrderEvent (Object source, OrderBean orderBean) {
super(source);
this.orderBean = orderBean;
}
public OrderBean getOrderBean() {
return this.orderBean;
}
}
#Component
public class OrderEventListener{
#Autowired
private OrderRepository orderRepository;
#Order(5000)
#TransactionalEventListener
public void processStoreOrderEvent(StoreOrderEvent event) {
OrderBean orderbean = orderRepository.save(event.getOrderBean());
// return orderBean
}
}
#Service
public class OrderService{
#Autowired
private ApplicationContext applicationContext;
public OrderBean storeOrder(OrderVO vo) {
vo -> orderBean;
applicationContext.publishEvent(new StoreOrderEvent(this, orderBean));
// get my saved orderBean
}
}
As discussed with OrangeDog on comments. it's good to use service and then post event.
or Might use service and use ServiceLocatorFactoryBean to get custom service.