I have an annotation driven spring mvc project templated after the JBoss web mvc sample. (Spring, Hibernate, JPA 2.0)
I have a utility package where I want to put reusable classes for obviously utility functions.
Specifically I have a LogonUtilities class where I want to query a database to get information.
I autowire my DAO there but when I debug the DAO is always null and fails with that exception.
I have read and tried many things - I know I've probably come across the solution already - but missed something and moved on and tried something else. I probably am not googling the correct terms since annotations are new to me. (I've worked with spring & hibernate for years - but with xml)
I've added this to my applicationContext.xml
<context:component-scan base-package="util"/>
which I thought was all I needed to do.
This is what I currently have in my LogonUtility class - but it doesn't work, keywordDao is always null. I think I could probably get it to work if I wired the DAO to a LogonUtility bean in the applicationContext (the old way) but I would think there's a better way to do it with annotations.
#Service
public class LogonUtilities {
#Autowired private KeywordDao keywordDao;
My application isn't brand new, I probably have ten working controllers and over a dozen working DAOs at this point, including a Keyword Controller and DAO that already does CRUD operations, so I don't think my setups with that stuff is incorrect.
I just have some code I want to reuse that pulls from a database.
Thanks in advance.
*in my code it's actually called "TrainingKeyword" not "Keyword"
This is the nullPointer error because the DAO is null
10:52:07,673 ERROR [io.undertow.request] (default task-1) UT005023: Exception handling request to /Training/Home: java.lang.NullPointerException
at util.LogonUtilities.trainingOffices(LogonUtilities.java:59) [classes:]
at filter.LogonFilter.doFilter(LogonFilter.java:100) [classes:]
at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:346) [spring-web-3.1.1.RELEASE.jar:3.1.1.RELEASE]
This is the code where the error happens
//Set TrainingOffices
List<TrainingKeyword> kList1 = keywordDao.getAllTrainingKeywordsByName("Level 200 Training Offices");
I solved my problem by listening to your ideas and with help from this question.
JPA is not Autowiring
Basically I had already tried everything that worked - but never all together. I was constantly making edits to my code trying to get it to work and always had either something missing or something bad. For anyone with a similar question here are the steps
In my LogonFilter I added
#Autowired private LogonUtilities lu
In my LogonUtilites class I added
#Autowired private TrainingKeywordDao keywordDao;
There was no need to add the LogonUtility bean to my applicationContext - I took it out and it still works.
Thank you to all that helped - your ideas kept making me rethink what I was doing.
You are trying to do a #Autowired private KeywordDao keywordDao; but you not getting any autowiring error. but #Autowired is by default #Autowired(required=true) meaning that these dependencies are by default mandatory, and throw an error if not met.
No autowiring error is received, so the conclusion is that it seems that this class is not being scanned for autowiring at all.
If it would then an error would be thrown. Try to see why the class is not being autowired, here are some common causes:
the package where the class is placed is not being scanned, is the name of the classes package util or a subpackage?
The scanning is being done in the wrong spring context. Most Spring applications have two contexts, one root context and one servlet dispatcher context. Try to move the component scan <context:component-scan base-package="util"/> from one context to the other, by copying this configuration line from one XML file to the other.
Make sure that base-package is the fully qualified path of the service from the root on, and make sure that KeywordDao is annotated with #Repository.
Related
I can sometimes get the annotation via [object].getClass().isAnnotationPresent([Annotation.class])
but sometimes not.
So I turn on the debug mode and find the difference:
In the fist picture, b.getClass() return the actual class: stan.beans.HisBean
But in the second picture, it actually return something different, looks like a modified class by Spring framework so I use the proxied word in the title:
class packagepath.Handler$$EnhancerBySpringCGLIB$$da96cafa
Thanks to #Teppic I figure out we can use AopProxyUtils.ultimateTargetClass() to get the non-proxied class
But my question now is :
When will SpringCGLB proxy the class? Is there any configuration I can change? Cause I think both my screenshots use the same configuration. They almost shadow each other.
Important Info Thanks to #M. Deinum
The second bean class(proxied one) has Spring Cache #Cacheable annotation on some methods
So, I have an application running on WildFly10, which uses JSF, Spring (DI), JPA, Spring Data;
Right now we're trying to move it to CDI and remove Spring(DI). For now we'll keep Spring Data.
So, I set up CDI and made an EntityManager producer.
#Produces
#Dependent
#PersistenceContext
public EntityManager entityManager;
So, I'm able to inject repositories with CDI and all.
However on my original environment we had a custom repository factory,that was defined in my SpringConfiguration like this:
#EnableJpaRepositories(basePackages = {"com.foo.repository" }, repositoryFactoryBeanClass=CustomJpaRepositoryFactoryBean.class)
So, the question is, how can I define this repositoryFactoryBeanClass=CustomJpaRepositoryFactoryBean.class on a CDI environment?
The current implementation doesn't allow the configuration of the JpaRepositoryFactoryBean as one can see from the code where it gets instantiated.
So I guess you have the following options:
reimplement the instantiation process.
open a feature request.
do 2. and 1. in a reusable way and submit the result as a PR for the issue.
When trying to solve this problem I found that the custom impl was not being picked up. The solution suggested in this question helped me however: https://stackoverflow.com/a/38541669/188624
Basically is uses Java8 default interface method to provide the additional functionality. I had to use the "CDI.current().select" method to get hold of the entity manager though as property injection of course won't work.
I tested with Spring Data JPA 2.0.0
I'm trying to get a better understanding of the #Autowired annotations component scanning, but all the examples I found so far use context.getBean(..) at some point to get at least one Bean to start with.
I also read that doing that is considered bad practice , but I can't seem to find any information on how to do it without context.getBean(..)
Could somebody please enlighten me with an example and information on how to do this ?
Define your bean in xml and use
<context:component-scan base-package="com" />
<mvc:annotation-driven />
Bean def
<bean id="processEngine" class="com.processEngine">
<property name="processEngineConfiguration" ref="processEngineConfiguration" />
</bean>
now you can get bean as following
#Autowired
private ProcessEngine processEngine;
how it works
spring scans the bean's recipes either from xml or java configuration. then spring creates a beanDefinitions which are 'loaded' into BeanFactory. BeanFactory triggers a set of BeanPostProcessors (BPP) which are scanning classes for particular annotations like Autowired/Resource/PostProcessor and etc. and do appropriate actions. in case when your class contains #Autowired annotation, AutowiredAnnotationBeanPostProcessor would auto wire required field (dependencies), and when creation of an object is done and all BPP worked out, object is ready to be used by the app, from this point your code can get 'ready' objects from container.
there are some cases when you would need to access this beans from the code which is out of spring's control and not managed by container. in order to do so, you would need to get the ApplicationContext (container) and call #getBean specifying either name or type. using applicationContext directly is not a good practice because there are some problems that you can come to, f.ex. id of a bean might be changed and if you refer to bean by id then NPE would be thrown.
configuration
there are several approaches to configure spring to scan the classes for finding bean recipes. one would be defining component-scan, in this case classes which are located in the path that you've set and having any of valid spring annotations like #Component, #Service, #Repository, #Controller (for web container) would be considered. another way would be specifying each bean separately using <bean> or #Bean.
examples.
if you want to create a web app then you should see DispatcherServlet with ContextLoaderListener classes. this classes would boot your app and load everything according to configuration. f.ex. here,
but if you want to create a desktop app, then you would end up with something like this
From time to time (usually when not using Spring Boot), I use something along the lines of the following code:
public static <T> T autowire(ApplicationContext ctx, T bean) {
ctx.getAutowireCapableBeanFactory().autowireBean(bean);
return bean;
}
In my main, I create an instance of the main application class that contains a few #Autowired annotations for the main services / entry points to my Spring application.
I noticed that the following is not working in a class marked as a #Controller:
#Autowired
SessionFactory sessionFactory;
#ResponseBody
#Transactional
#RequestMapping(method = RequestMethod.GET , value = "/map")
public ArrayList<PhotoDTO> getPhotos(...someParams) {
Entity result sessionFactory.getCurrentSession()... //do some manipulation
return result;
}
when I call the URL, I get an error saying that the method is not transactional (although, as you can see, it is marked as one)
If I copy this method to a another class called MyService and call it from the controller instead, it works perfectly
Is this some sort of a Spring advice (a conspiracy to make me use more classes more or less)?
Don't do transactions in your controller. Put them in your service layer classes.
Separate your code into model-view-controller.
Yes it is a conspiracy. It enables to you to share code between controllers/views without repeating code. And also stops rollbacks of transactions unnecessarily (for exceptions unrelated to the actual transaction).
It might seem like more code to begin with, but in the long run it is much more manageable and simpler to develop.
Probably you have two application contexts here: main Spring context loaded by ContextLoaderListener and a child context loaded by DispatcherServlet. You need to put <tx:annotation-driven /> in the configuration loaded by the child context too. If you show us your web.xml file maybe I can help you more.
Anyway, as #NimChimpsky says, is usually not a good practice to manage transactions in your controller layer.
I've been trying to get a sample JMX MXBean working in a Spring-configured webapp, but any basic attributes on the MXBean are coming up as UNDEFINED when I connect with jconsole.
Java interface/classes:
public interface IJmxBean { // marker interface for spring config, see below
}
public interface MgmtMXBean { // lexical convention for MXBeans - mgmt interface
public int getAttribute();
}
public class Mgmt implements IJmxBean, MgmtMXBean { // actual JMX bean
private IServiceBean serviceBean; // service bean injected by Spring
private int attribute = 0;
#Override
public int getAttribute() {
if(serviceBean != null) {
attribute = serviceBean.getRequestedAttribute();
}
return attribute;
}
public void setServiceBean(IServiceBean serviceBean) {
this.serviceBean = serviceBean;
}
}
Spring JMX config:
<beans>
<context:component-scan base-package="...">
<context:include-filter type="assignable" expression="...IJmxBean" />
</context:component-scan>
<context:mbean-export />
</beans>
Here's what I know so far:
The element is correctly instantiating a bean named "mgmt". I've got logging in a zero-argument public constructor that indicates it gets constructed.
is correctly automatically detecting and registering the MgmtMXBean interface with my Tomcat 6.0 container. I can connect to the MBeanServer in Tomcat with jconsole and drill down to the Mgmt MXBean.
When examining the MXBean, "Attribute" is always listed as UNDEFINED, but jconsole can tell the correct type of the attribute. Further, hitting "Refresh" in jconsole does not actually invoke the getter method of "Attribute"- I have logging in the getter method to indicate if it is being invoked (similar to the constructor logging that works) and I see nothing in the logs.
At this point I'm not sure what I'm doing wrong. I've tried a number of things, including constructing an explicit Spring MBeanExporter instance and registering the MXBean by hand, but it either results in the MBean/MXBean not getting registered with Tomcat's MBean server or an Attribute value of UNDEFINED.
For various reasons, I'd prefer not to have to use Spring's #ManagedResource/#ManagedAttribute annotations.
Is there something that I'm missing in the Spring docs or MBean/MXBean specs?
ISSUE RESOLVED: Thanks to prompting by Jon Stevens (above), I went back and re-examined my code and Spring configuration files:
Throwing an exception in the getAttribute() method is a sure way to get "Unavailable" to show up as the attribute's value in JConsole. In my case:
The Spring JMX config file I was using was lacking the default-autowire="" attribute on the root <beans> element;
The code presented above checks to see if serviceBean != null. Apparently I write better code on stackoverflow.com than in my test code, since my test code wasn't checking for that. Nor did I have implements InitializingBean or #PostConstruct to check for serviceBean != null like I normally do on almost all the other beans I use;
The code invoking the service bean was before the logging, so I never saw any log messages about getter methods being entered;
JConsole doesn't report when attribute methods throw exceptions;
The NPE did not show up in the Tomcat logs.
Once I resolved the issue with serviceBean == null, everything worked perfectly. Regardless, +1 to Jon for providing a working demo, since there are literally 50 different ways to configure MBeans/MXBeans within Spring.
I've recently built a sample Spring based webapp that very cleanly enables JMX for latest versions of Spring, Hibernate and Ehcache.
It has examples for both EntityManager based access and DAO access (including transactions!). It also shows how to do annotation based injection in order to negate having to use Spring's xml config for beans. There is even a SpringMVC based example servlet using annotations. Basically, this is a Spring based version of a fairly powerful application server running on top of any servlet engine.
It isn't documented yet, but I'll get to that soon. Take a look at the configuration files and source code and it should be pretty clear.
The motivation behind this is that I got tired of all of the crazy blog posts with 50 different ways to set things up and finally made a single simple source that people can work from. It is up on github so feel free to fork the project and do whatever you want with it.
https://github.com/lookfirst/fallback