How to observe the Application Context at runtime (while debugging) - java

I am debugging my Java Spring service and I get an #Autowired variable as null, when it shouldn't be.
Since I have declared the service's class as #Service, I want to double-check that my bean was scanned by Spring and included in the Application Context.
Therefore, I want to be able to observe in Eclipse the contents of the Application Context.
How is this possible?

inject ApplicationContext into a bean that you can debug and call #getBeanDefinitionNames

I am not sure if this is the best way but without adding any extra framework,if you just want to check if dependencies are injected correctly or not ,you can firstly remove #Autowired annotation from the fields.
Now create a parameterized constructor and annotate the constructor with #Autowired. Spring will try to inject all the beans through the constructor.
http://www.tutorialspoint.com/spring/spring_autowired_annotation.htm
Now you can put breakpoint inside the constructor to check what value is getting injected.
Hope this helps.

There is a workaround to get the WebApplicationContext in the debugger without changing the source code.
The RequestContextUtils#findWebApplicationContext method will help us with this.
You need to pass the current request to it, which can also be obtained using the static method:
((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest()
By combining these calls, you can get the context anywhere in the web application in the debugger and call any of its methods:
RequestContextUtils
.findWebApplicationContext(((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest())
.getBeanDefinitionNames();
Slightly prettier version:
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest();
WebApplicationContext webApplicationContext = RequestContextUtils.findWebApplicationContext(request);
webApplicationContext.getBeanDefinitionNames();

you can use log4j.jar to output all the WARNINGS, DEBUGS, INFO once you start your server. Follow the below link http://www.tutorialspoint.com/spring/logging_with_log4j.htm. I have a working example at my other laptop, can post the code. Let me know if you need it

Related

To provide nicer logging when a Spring property is invalid

Using a application.properties file my Spring Boot app can use some property values in it. A way to make sure a mandatory value must present is to add an annotation #Value for the property. The problem with this is the app fails miserably if the property value is not there in the properties file.
I am after a nicer less horrible way to say printing out a log line about "Property A is missing" instead of a whole stack trace. Is there a way to do this while still using #Value to initialise the properties? For example, property A is mandatory, an error is logged before app exits; property B is missing but not mandatory, a warning is logged and app continues.
If you can identify all property, then you can write a method in Application class with #Postconstruct, and inside your method, you can manually validate and log them
#Autowired
private Environment environment;
#PostConstruct
private void validateProperties() {
environment.getProperty(key);
.....
......
}
Alternatively, you can write your custom EnvironmentPostProcessor, and iterate all properties and log whichever is null/empty.
As you're using spring-boot consider creating a #ConfigurationProperties class rather than using the #Value annotation.
By doing that you can do your validations using Bean Validation, also in the same class, you can implement the interface InitializingBean and add extra validations/log messages as you with.
Follow this link on Spring's official docs to read more about #ConfigurationProperties.

In spring, is there a way to autowire the first bean?

In the example below, is there a way to avoid doing a context.getBean()? All the other beans subsequently used by the testService get autowired. (It is a console application)
public class Test {
private static ITestService testService;
private static ApplicationContext context;
public static void main(String[] args) {
context = new ClassPathXmlApplicationContext(
new String[]{"/META-INF/spring/app-context.xml"});
ITestService testService = context.getBean(ITestService.class);
}
}
I tried adding autowire annotation to ApplicationContext, but it didnt work. Besides how does it know where my app-context.xml is located if I autowire it?
Update: I found what I needed over here
Right, you're missing out a few details here.
Below is a short explanation of how Spring works.
1- The application context is loaded somehow (we will get there soon).
2- After loaded, app context will initialize/create all beans defined. Here is when beans get injected as dependencies. After this Whenever you get a bean back from the app context, that bean is all initialized and ready to go with all the dependencies in place (considering everything went fine).
RE the first step, there are a few way to automate the Spring initialization.
One way is what you are doing, explicitly instantiating one. Other way could be via a context listener in case you're in a web environment, or maybe with the #RunWith. (You can find more here)
In your case, I believe you are looking for using Spring in a (Unit?!?) test environment so you are looking for something like
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration
public class MyTest {
#Autowired
private ApplicationContext applicationContext;
// class body...
}
further details here
http://docs.spring.io/spring/docs/current/spring-framework-reference/htmlsingle/#testing
You cannot call beans without initializing the application context first.
Secondly in your case Test class should be bean itself to be managed by spring then to autowire ITestService. The purpose of Application context as a container is to manage the bean lifecycle so u need to initialize it first by ClassPathXmlApplicationContextand then it will initialize all beans declared by you in ur xml file. About avoiding the getBean method if you are using servlets for creating web app you can avoid getBean. If not you should handle it manually.
I agree with what #Desorder has said. When I started working with #RunWith(SpringJUnit4ClassRunner.class) and #ContextConfiguration, I used to get my test cases working. But it took me some time to understand how these two are working internally and their default configurations.
If you would like to take some different approach and would like to try without #RunWith and #ContextConfiguration, take a look at the link - TUTORIAL: JUNIT #RULE. With this, you will be very clear which spring xml file locations are provided.

Spring 4 conditional - Accessing a resource

Doing my first steps with spring 4 I tried the #Conditional annotation following this article.
My problem -
I would like to get access to a classpath resource (basically a properties file) from method matches in class OnSystemPropertyCondition.
To do that currently I'm loading the required properties file from the matches method every time it is invoked (which means for every class annotated with the ConditionalOnSystemProperty annotation).
This is a bit ugly. I thought that an elegant solution would be to simply autowire my resource or some properties (using the #Value annotation) but this can't be done since this class gets instanciated before the beans.
Any suggestions than can help me avoid reload this resource again and again?
The single method of the annotation gets in its signature the input param ConditionContext context. You can obtain an Environment from the context by calling context.getEnvironment(). The environment gives access to all my resources (look at this to see how to get access to your resources via spring environment).

Spring: autowiring DAO into a utility class not working

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.

Spring #Value annotation always evaluating as null?

So, I have a simple properties file with the following entries:
my.value=123
another.value=hello world
This properties file is being loaded using a PropertyPlaceHolderConfigurer, which references the properties file above.
I have the following class, for which I'm trying to load these properties in to like so:
public class Config
{
#Value("${my.value}")
private String mValue;
#Value("${another.value}")
private String mAnotherValue;
// More below...
}
The problem is that, mValue and mAnotherValue are ALWAYS null... yet in my Controllers, the value is being loaded just fine. What gives?
If instances of Config are being instantiated manually via new, then Spring isn't getting involved, and so the annotations will be ignored.
If you can't change your code to make Spring instantiate the bean (maybe using a prototype-scoped bean), then the other option is to use Spring's load-time classloader weaving functionality (see docs). This is some low-level AOP which allows you to instantiate objects as you normally would, but Spring will pass them through the application context to get them wired up, configured, initialized, etc.
It doesn't work on all platforms, though, so read the above documentation link to see if it'll work for you.
I had similar issues but was a newbie to Spring.
I was trying to load properties into an #Service, and tried to use #Value to retrieve the property value with...
#Autowired
public #Value("#{myProperties['myValue']}") String myValue;
I spend a whole day trying various combinations of annotations, but it always returned null.
In the end the answer as always is obvious after the fact.
1) make sure Spring is scanning your class for annotations by including the package hierachy
In your servlet.xml (it will scan everything below the base value you insert.
2) Make sure you are NOT 'new'ing the class that you just told Spring to look at. Instead, you use #Autowire in the #Controller class.
Everything in Spring is a Singleton, and what was happening was Spring loaded the values into its Singleton, then I had 'new'ed another instance of the class which did not contain the newly loaded values so it was always null.
Instead in the #Controller use...
#Autowired
private MyService service;
Debugging...
One thing I did to find this was to extend my Service as follows...
#Service
public class MyService implements InitializingBean
Then put in debug statements in...
#Override
public void afterPropertiesSet() throws Exception {
// TODO Auto-generated method stub
LOGGER.debug("property myValue:" + myValue);
}
Here I could see the value being set on initialization, and later when I printed it in a method it was null, so this was a good clue for me that it was not the same instance.
Another clue to this error was that Tomcat complained of Timeouts trying to read from the Socket with Unable to parse HTTPheader... This was because Spring had created an instance of the service and so had I, so my one was doing the real work, and Spring was timing out on its instance.
See my answer here.
I ran into the same symptoms (#Value-annotated fields being null) but with a different underlying issue:
import com.google.api.client.util.Value;
Ensure that you are importing the correct #Value annotation class! Especially with the convenience of IDEs nowadays, this is a VERY easy mistake to make (I am using IntelliJ, and if you auto-import too quickly without reading WHAT you are auto-importing, you might waste a few hours like I did).
The correct import is:
org.springframework.beans.factory.annotation.Value
As its working with #Controller, it seems you are instantiating Config yourself. Let the Spring instantiate it.
You can also make your properties private, make sure your class is a Spring bean using #Service or #Component annotations so it always gets instantiated and finally add setter methods annotated with #Value . This ensures your properties will be assigned the values specified in your application.properties or yml config files.
#Service
public class Config {
private static String myProperty;
private static String myOtherProperty;
#Value("${my.value}")
public void setMyProperty(String myValue) {
this.myProperty = myValue;}
#Value("${other.value}")
public void setMyOtherProperty(String otherValue) {
this.myOtherProperty = otherValue;}
//rest of your code...
}
Add <context:spring-configured /> to you application context file.
Then add the #Configurable annotation to Config class.
In my case in my unit test, executeScenarioRequest always is null
#RunWith(SpringRunner.class)
#ExtendWith(MockitoExtension.class)
class ScenarioServiceTestOld {
#Value("classpath:scenario/SampleScenario.json")
Resource executeScenarioRequest;
Change #ExtendWith(MockitoExtension.class) to #ExtendWith(SpringExtension.class)

Categories

Resources