Spring annotation #Value - What am I missing? - java
I've inherited some Java code. Several classes have their instance variables initialized from property values in /WEB-INF/servlet.properties like this:
#Value("${context.root}")
private String contextRoot;
When I try this in a new class, the instance variable is not initialized. My class is constructed similarly to the one that works, but it is in a different package (com.company.app.utilities vs. com.company.app.service) Both import the same class:
import org.springframework.beans.factory.annotation.Value;
Both have corresponding public getter and setter methods.
I've reviewed some Spring documentation and /WEB-INF/applicationContext.xml, but I don't see anything obvious that I need to configure.
Any assistance is greatly appreciated.
Update:
I see the following entries in the log:
[localhost-startStop-1] 03 Dec 2014 02:47:10,791 INFO : org.springframework.context.support.PropertySourcesPlaceholderConfigurer - Loading properties file from ServletContext resource [/WEB-INF/servlet.properties]
[localhost-startStop-1] 03 Dec 2014 02:47:10,938 INFO : org.springframework.beans.factory.support.DefaultListableBeanFactory - Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory#601e8f7d: defining beans [...,contactServiceImpl,s3Transfer,...]; parent: org.springframework.beans.factory.support.DefaultListableBeanFactory#32f5f812
I've omitted all other singletons from the log entry, to highlight that both the original class and my class are in the list; however, I created a constructor, whereas the original class has no constructor. The next line in the log is the exception I throw in a getter method when the value is null, caught inside the constructor:
[localhost-startStop-1] 03 Dec 2014 02:47:12,730 ERROR: com.company.app.utilities.S3Transfer - bucketName is null!
java.lang.Exception: bucketName is null!
at com.company.app.utilities.S3Transfer.getBucketName(S3Transfer.java:129)
at com.company.app.utilities.S3Transfer.<init>(S3Transfer.java:48)
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:57)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.lang.reflect.Constructor.newInstance(Constructor.java:526)
at org.springframework.beans.BeanUtils.instantiateClass(BeanUtils.java:148)
at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:87)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateBean(AbstractAutowireCapableBeanFactory.java:1000)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:953)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:487)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:458)
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:295)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:223)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:292)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:194)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:626)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:932)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:479)
at org.springframework.web.servlet.FrameworkServlet.configureAndRefreshWebApplicationContext(FrameworkServlet.java:651)
at org.springframework.web.servlet.FrameworkServlet.createWebApplicationContext(FrameworkServlet.java:599)
at org.springframework.web.servlet.FrameworkServlet.createWebApplicationContext(FrameworkServlet.java:665)
at org.springframework.web.servlet.FrameworkServlet.initWebApplicationContext(FrameworkServlet.java:518)
at org.springframework.web.servlet.FrameworkServlet.initServletBean(FrameworkServlet.java:459)
at org.springframework.web.servlet.HttpServletBean.init(HttpServletBean.java:136)
at javax.servlet.GenericServlet.init(GenericServlet.java:160)
...
Should I remove the constructor? If so, is there additional Spring configuration to instantiate a singleton of this class? Thanks.
Update 2014-12-03:
I think I've been away from Java too long, as the last time I coded AOP, there was no Spring Framework, and it's got me a bit confused. When you say "instantiated by Spring", does this mean to place #Autowired in the class that uses my new class? I've made this change and I've rewritten my class to implement an interface, but now Tomcat fails to restart properly. Code, properties and logs below:
package com.company.app.utilities;
import com.company.app.bean.Contact;
import java.io.InputStream;
public interface S3Transfer {
String storeContactProfilePicture(Long idUser, Contact contact);
String storeContactProfilePicture(Long idUser, Long idContact, InputStream inStream);
String storeUserProfilePicture(Long idUser, String fileName, String accountType);
}
package com.company.app.utilities;
import com.amazonaws.AmazonClientException;
import com.amazonaws.AmazonServiceException;
import com.amazonaws.services.s3.AmazonS3;
import com.amazonaws.services.s3.AmazonS3Client;
import com.amazonaws.services.s3.model.PutObjectRequest;
import com.company.app.bean.Contact;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Value;
public class S3TransferImpl implements S3Transfer {
private final AmazonS3 s3client = new AmazonS3Client();
private final Logger logger = Logger.getLogger(getClass());
#Value("${context.root}")
private String contextRoot;
#Value("${s3.bucket.name}")
private String bucketName;
#Value("${contact.profile.picture}")
private String contactProfilePictureKey;
#Value("${user.profile.picture}")
private String userPictureKey;
public String storeContactProfilePicture(Long idUser, Contact contact) {
String keyName = getContactProfilePictureKey().replaceAll("<<idUsr>>", idUser.toString()).replaceAll("<<idContact>>", contact.getIdContact().toString());
String fileName = contact.getPicture();
storeObjectFromFileName(fileName, keyName);
return contextRoot + keyName;
}
public String storeContactProfilePicture(Long idUser, Long idContact, InputStream inStream) {
String keyName = getContactProfilePictureKey().replaceAll("<<idUsr>>", idUser.toString()).replaceAll("<<idContact>>", idContact.toString());
storeObject(inStream, keyName);
return contextRoot + keyName;
}
public String storeUserProfilePicture(Long idUser, String fileName, String accountType) {
String keyName = getUserPictureKey().replaceAll("<<idUsr>>", idUser.toString()).replace("<<socialNetwork>>", accountType);
storeObjectFromFileName(fileName, keyName);
return contextRoot + keyName;
}
private void storeObjectFromFileName(String fileName, String keyName) {
try {
logger.info("Uploading " + fileName + " to " + keyName);
InputStream inStream = new URL(fileName).openStream();
storeObject(inStream, keyName);
} catch (IOException e) {
logger.error(e.getMessage(), e);
}
}
private void storeObject(InputStream inStream, String keyName) {
try {
this.s3client.putObject(new PutObjectRequest(getBucketName(), keyName, inStream, null));
} catch (AmazonServiceException ase) {
logger.error("Caught an AmazonServiceException, which "
+ "means your request made it "
+ "to Amazon S3, but was rejected with an error response"
+ " for some reason.");
logger.error("Error Message: " + ase.getMessage());
logger.error("HTTP Status Code: " + ase.getStatusCode());
logger.error("AWS Error Code: " + ase.getErrorCode());
logger.error("Error Type: " + ase.getErrorType());
logger.error("Request ID: " + ase.getRequestId());
} catch (AmazonClientException ace) {
logger.error("Caught an AmazonClientException, which "
+ "means the client encountered "
+ "an internal error while trying to "
+ "communicate with S3, "
+ "such as not being able to access the network.");
logger.error("Error Message: " + ace.getMessage());
} catch (Exception e) {
logger.error(e.getMessage(), e);
}
}
public String getContextRoot() {
return contextRoot;
}
public void setContextRoot(String contextRoot) {
this.contextRoot = contextRoot;
}
public String getBucketName() {
return bucketName;
}
public void setBucketName(String bucketName) {
this.bucketName = bucketName;
}
private String getContactProfilePictureKey() {
return contactProfilePictureKey;
}
private void setContactProfilePictureKey(String contactProfilePictureKey) {
this.contactProfilePictureKey = contactProfilePictureKey;
}
private String getUserPictureKey() {
return userPictureKey;
}
private void setUserPictureKey(String userPictureKey) {
this.userPictureKey = userPictureKey;
}
}
The classes that use S3Transfer now have the following code:
#Autowired
private S3Transfer s3Transfer;
Both /WEB-INF/applicationContext.xml and /WEB-INF/app-web-servlet.xml have the following elements within the complex bean element:
<context:annotation-config />
<context:component-scan base-package="com.company.app" />
<context:property-placeholder location="/WEB-INF/servlet.properties" />
When I restart Tomcat, initialization fails. Here are some of the relevant log entries:
[localhost-startStop-1] 03 Dec 2014 18:39:03,407 INFO : org.springframework.beans.factory.xml.XmlBeanDefinitionReader - Loading XML bean definitions from ServletContext resource [/WEB-INF/applicationContext.xml]
[localhost-startStop-1] 03 Dec 2014 18:39:03,926 INFO : org.springframework.context.annotation.ClassPathBeanDefinitionScanner - JSR-250 'javax.annotation.ManagedBean' found and supported for component scanning
[localhost-startStop-1] 03 Dec 2014 18:39:05,990 INFO : org.springframework.context.annotation.ClassPathBeanDefinitionScanner - JSR-250 'javax.annotation.ManagedBean' found and supported for component scanning
[localhost-startStop-1] 03 Dec 2014 18:39:07,983 INFO : org.springframework.context.support.PropertySourcesPlaceholderConfigurer - Loading properties file from ServletContext resource [/WEB-INF/servlet.properties]
[localhost-startStop-1] 03 Dec 2014 18:39:08,708 INFO : org.springframework.beans.factory.support.DefaultListableBeanFactory - Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory#63655d7a: defining beans [... {long list, but s3TransferImpl is not in the list} ...]; root of factory hierarchy
[localhost-startStop-1] 03 Dec 2014 18:39:10,667 INFO : org.springframework.jdbc.datasource.DriverManagerDataSource - Loaded JDBC driver: com.mysql.jdbc.Driver
[localhost-startStop-1] 03 Dec 2014 18:39:20,152 ERROR: org.springframework.web.context.ContextLoader - Context initialization failed
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.security.filterChains': Cannot resolve reference to bean 'org.springframework.security.web.DefaultSecurityFilterChain#0' while setting bean property 'sourceList' with key [0]; nested exception is ... {long list of nested exceptions}...; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [com.company.app.utilities.S3Transfer] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {#org.springframework.beans.factory.annotation.Autowired(required=true)}
at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:329)
Update 2014-12-03 14:50 EST:
Apparently, both my interface and class needed an #Service annotation, as Tomcat restarted successfully. What is the purpose of this annotation?
The package of the new class i.e. com.company.app.service needs to be added to the xml file which has the spring configuration.
You need to add this to your spring XML configuration file
<beans>
<context:component-scan base-package="com.package.containing.yourclass" />
</beans>
You need to this so that Spring understands which classes it needs to scan for annotations and/or creating beans.
Could you please share the code where you are trying to access the variable. If it is inside contructor, then you will get error. As singleton beans being instiated during loading will not be able to access these values from property configurator. You may consider to move your code to in-it method, so that your variable will set while accessing the field.
Also, confirm if your class is being instantited by spring container, not by some other means like new operator
Related
Class required a bean of type 'java.lang.String' that could not be found
I try to a mailservice in Spring. I use Spring-Boot version 2.1.7.Release and amazon-sqs-java-messaging-lib version 1.0.8. My code looks like: #Service #RequiredArgsConstructor public class MailService { private static final Logger logger = Logger.getLogger(MailService.class.getName()); private final AmazonSQS amazonSQS; #Value("${aws.sqs.queue.mail}") private final String sqsQueueMail; public void sendMail(final SQSMailParams mailParams) { final String queueUrl = amazonSQS.getQueueUrl(sqsQueueMail).getQueueUrl(); try { final String messageBody = SQSMailParams.createSQSMailParams(mailParams, mailParams.getTemplateKey(), mailParams.getProcessId()).toJson(); final SendMessageRequest sendMessageRequest = new SendMessageRequest(queueUrl, messageBody); sendMessageRequest.setMessageGroupId("TOLL-BOX-MAIL"); amazonSQS.sendMessage(sendMessageRequest); logger.info("TOLL-BOX mail added to mail queue"); } catch (JsonProcessingException e) { logger.error("Mail cannot be added to the mail queue: " + String.join(",", mailParams.recipients) + "." + e); } } } But i get the following failure by running the code. 2020-03-02 07:34:00.242 ERROR 10568 --- [ main] o.s.b.d.LoggingFailureAnalysisReporter : *************************** APPLICATION FAILED TO START *************************** Description: Parameter 1 of constructor in de.svg.tollbox.service.MailService required a bean of type 'java.lang.String' that could not be found. Action: Consider defining a bean of type 'java.lang.String' in your configuration. Disconnected from the target VM, address: '127.0.0.1:43565', transport: 'socket' Process finished with exit code 1 Could someone tell me what im doing wrong thank you.
Remove final from sqsQueueMail. #Value("${aws.sqs.queue.mail}") private String sqsQueueMail; That should fix your issue. Somehow, with #RequiredArgsConstructor, the #Value annotation for the variable is not resolved which made the application to look for a bean of type String
Сreate lombok.config file in the root of project and add following line: lombok.copyableAnnotations += org.springframework.beans.factory.annotation.Value That will allow you to use #Value with final field and with #RequiredArgsConstructor
Arquillian does not find classes
I set up a arquillian test to test my EJB and JPA layer: #RunWith(Arquillian.class) public class ClientTest { #EJB private ClientService client; #Deployment public static Archive<?> createDeployment() { return ShrinkWrap.create(WebArchive.class, "test.war") .addPackage(Client.class.getPackage()) .addPackage(ClientService.class.getPackage()) .addPackage(Client_.class.getPackage()) .addAsLibrary(new File("C:\\...\\ojdbc6.jar")) .addAsManifestResource(EmptyAsset.INSTANCE, "beans.xml") .addAsManifestResource("test-persistence.xml", "persistence.xml"); } #Test public void testCreate() { Assert.assertNotNull("Client not null", client); Client c = client.getClientById(1L); assertNotNull(c); } } Now, the log is telling me that the classes could not be found: Okt 12, 2015 9:43:17 AM org.glassfish.weld.BeanDeploymentArchiveImpl handleEntry WARNUNG: Error while trying to load Bean Class WEB-INF.classes.com.xyz.aip.common.AbstractEntity : java.lang.ClassNotFoundException: WEB-INF.classes.com.xyz.aip.common.AbstractEntity Okt 12, 2015 9:43:17 AM org.glassfish.weld.BeanDeploymentArchiveImpl handleEntry WARNUNG: Error while trying to load Bean Class WEB-INF.classes.com.xyz.aip.common.AbstractEntity_ : java.lang.ClassNotFoundException: WEB-INF.classes.com.xyz.aip.common.AbstractEntity_ I looked into the generated WAR-File and there is a - META-INF - WEB-INF - classes - com - xyz - aip - common - AbstractEntity.class Any ideas?
what I would try is: .addPackage(Client.class.getPackage().getName())
Why spring init-method destroy-method methods behaving different?
I am new to springs. I am trying to call init and destroy method for different bean invoking My init method is called from only "FileSystemResource" Why it was not called from others? public class DefaultMessage { private String message = "Basic Bean injecting"; public String getMessage() { return message; } public void setMessage(String message) { this.message = message; } public DefaultMessage(String message) { this.message = message; } public DefaultMessage() { } public void init(){ System.out.println("Testing init."); } public void destory(){ System.out.println("Spring Container is destroyed."); } My XML is <bean id="basicBean" class="com.sarma.spring.core.DefaultMessage" init-method="init" destroy-method="destory"></bean> Main class //Type 1 ApplicationContext applicationContext =new ClassPathXmlApplicationContext("DefaultMessage.xml"); //Basic Bean Testing DefaultMessage message = (DefaultMessage) applicationContext.getBean("basicBean"); log.info(message.getMessage()); log.info("---------------------------ApplicationContext End------------------------------"); //Type 2 Resource res = new FileSystemResource("C:\\Sarma\\Spring\\SpringEx\\src\\resource\\DefaultMessage.xml"); BeanFactory factory = new XmlBeanFactory(res); DefaultMessage message1 = (DefaultMessage) factory.getBean("basicBean"); log.info("Test "+message1.getMessage()); log.info("- ---------------------------FileSystemResource End------------------------------"); //Type 3 ClassPathResource res1 = new ClassPathResource("DefaultMessage.xml"); BeanFactory factory1 = new XmlBeanFactory(res1); DefaultMessage message2 = (DefaultMessage) factory1.getBean("basicBean"); log.info("Test "+message2.getMessage()); log.info("- ---------------------------ClassPathResource End-------------------------------"); //Type4 ConfigurableApplicationContext context = new ClassPathXmlApplicationContext(new String[] {"DefaultMessage.xml"}); DefaultMessage message3 = (DefaultMessage) context.getBean("basicBean"); log.info(message3.getMessage()); context.close(); log.info("- ---------------------------ConfigurableApplicationContext End------------------"); OUTPUT 2013-09-18 13:49:22 INFO ClassPathXmlApplicationContext:513 - Refreshing org.springframework.context.support.ClassPathXmlApplicationContext#913750: startup date [Wed Sep 18 13:49:22 EDT 2013]; root of context hierarchy 2013-09-18 13:49:22 INFO XmlBeanDefinitionReader:316 - Loading XML bean definitions from class path resource [DefaultMessage.xml] 2013-09-18 13:49:22 INFO DefaultMessageMain:27 - Basic Bean injecting 2013-09-18 13:49:22 INFO DefaultMessageMain:29 - ---------------------------ApplicationContext End------------------------------ 2013-09-18 13:49:22 INFO XmlBeanDefinitionReader:316 - Loading XML bean definitions from file [C:\Sarma\Spring\SpringEx\src\resource\DefaultMessage.xml] Testing init. 2013-09-18 13:49:22 INFO DefaultMessageMain:36 - Test Basic Bean injecting 2013-09-18 13:49:22 INFO DefaultMessageMain:37 - - ---------------------------FileSystemResource End------------------------------ 2013-09-18 13:49:22 INFO XmlBeanDefinitionReader:316 - Loading XML bean definitions from class path resource [DefaultMessage.xml] 2013-09-18 13:49:22 INFO DefaultMessageMain:42 - Test Basic Bean injecting 2013-09-18 13:49:22 INFO DefaultMessageMain:43 - - ---------------------------ClassPathResource End------------------------------- 2013-09-18 13:49:22 INFO ClassPathXmlApplicationContext:513 - Refreshing org.springframework.context.support.ClassPathXmlApplicationContext#176e552: startup date [Wed Sep 18 13:49:22 EDT 2013]; root of context hierarchy 2013-09-18 13:49:22 INFO XmlBeanDefinitionReader:316 - Loading XML bean definitions from class path resource [DefaultMessage.xml] 2013-09-18 13:49:22 INFO DefaultMessageMain:47 - Basic Bean injecting 2013-09-18 13:49:22 INFO ClassPathXmlApplicationContext:873 - Closing org.springframework.context.support.ClassPathXmlApplicationContext#176e552: startup date [Wed Sep 18 13:49:22 EDT 2013]; root of context hierarchy 2013-09-18 13:49:22 INFO DefaultMessageMain:49 - - ---------------------------ConfigurableApplicationContext End------------------ My init method is called from only "FileSystemResource" Why it was not called from others? Why it is behaving different? It never called my destroy method
I'm going to copy your code to explain //Type 1 ApplicationContext applicationContext =new ClassPathXmlApplicationContext("DefaultMessage.xml"); //Basic Bean Testing DefaultMessage message = (DefaultMessage) applicationContext.getBean("basicBean"); The above will init() your bean. //Type 2 Resource res = new FileSystemResource("C:\\Sarma\\Spring\\SpringEx\\src\\resource\\DefaultMessage.xml"); BeanFactory factory = new XmlBeanFactory(res); DefaultMessage message1 = (DefaultMessage) factory.getBean("basicBean"); This will also init() your bean. //Type 3 ClassPathResource res1 = new ClassPathResource("DefaultMessage.xml"); BeanFactory factory1 = new XmlBeanFactory(res1); DefaultMessage message2 = (DefaultMessage) factory1.getBean("basicBean"); This will also init() your bean. //Type4 ConfigurableApplicationContext context = new ClassPathXmlApplicationContext(new String[] {"DefaultMessage.xml"}); DefaultMessage message3 = (DefaultMessage) context.getBean("basicBean"); log.info(message3.getMessage()); context.close(); This will also init() your bean. Because of the context.close(), all beans will be destroyed before the context being closed. If the destroy-method isn't being called, you can try with DisposableBean interface, but consider that bad practice as your classes start being dependent on Spring types.
I have implemented DisposableBean interface to my bean class and overrides destroy method and removed destroy-method method form my XML. Now destroy method is calling 3 times except ApplicationContext, Destroy method is calling from FileSystemResource, ClassPathResource, ClassPathXmlApplicationContext and not from ApplicationContext.
For ClassPathXmlApplicationContext, we can pass different xml's for example ConfigurableApplicationContext context = new ClassPathXmlApplicationContext(new String[] {"DefaultMessage.xml", "DefaultMessage1.xml}"); while closing ConfigurableApplicationContext it will close all resource which was opened, that why it closed all 3 FileSystemResource, ClassPathResource, ClassPathXmlApplicationContext.
#Value annotations inside my Java class don't load values from .properties file
Before asking this question I tried to follow the following questions which are similar: Injecting Properties using Spring & annotation #Value How can I inject a property value into a Spring Bean which was configured using annotations? Loading up properties file to a class in Spring However, in my case I am not using any web applications or Tomcat; I'm just trying to load a cluster.properties file into a regular Java project via Spring so I can then ingest dummy data into Accumulo. Also, I'm trying to load properties from a cluster.properties file, not from key value pairs defined in an xml file. Using what I learned from the links above and lots of reading on Spring, here's what I have: I created the following context.xml file: <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd"> <!-- Define the Spring Bean to load our cluster properties --> <bean id="props" class="accumuloIngest.LoadProperties"></bean> </beans> And here is a small snippet of what my cluster.properties file looks like: cluster.instance=instance cluster.username=user etc... Next, I created the following Spring main method under the class MainApp.java: package accumuloIngest; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class MainApp { // Spring main method used to load a cluster.properties file with the Spring framework public static void main(String[] args) { ApplicationContext ctx = new ClassPathXmlApplicationContext("context.xml"); LoadProperties myObj = LoadProperties.class.cast(ctx.getBean("props")); // Now print out the cluster.properties loaded by Spring to verify they aren't null StringBuffer springPropsBuffer = new StringBuffer(); springPropsBuffer.append("Printing out cluster.properties read via Spring..."); springPropsBuffer.append("\n\n"); springPropsBuffer.append("instanceName= "); springPropsBuffer.append(myObj.getInstanceName()); springPropsBuffer.append("\n"); springPropsBuffer.append("userName= "); springPropsBuffer.append(myObj.getUserName()); springPropsBuffer.append("\n"); springPropsBuffer.append("password= "); springPropsBuffer.append(myObj.getPassword()); springPropsBuffer.append("\n"); springPropsBuffer.append("zooServers= "); springPropsBuffer.append(myObj.getZooServers()); springPropsBuffer.append("\n"); springPropsBuffer.append("tableName= "); springPropsBuffer.append(myObj.getTableName()); springPropsBuffer.append("\n"); springPropsBuffer.append("dataFile= "); springPropsBuffer.append(myObj.getDataFile()); springPropsBuffer.append("\n"); springPropsBuffer.append("dataDelim= "); springPropsBuffer.append(myObj.getDataDelim()); springPropsBuffer.append("\n"); springPropsBuffer.append("rowCount= "); springPropsBuffer.append(myObj.getRowCount()); springPropsBuffer.append("\n"); System.out.println(springPropsBuffer.toString()); // now start data ingest myObj.startIngest(); // method that calls Ingester class to start data ingest } // end of main method } // end of MainApp class Spring loads my context.xml file and loads the Bean I called "props", but the values are still null. It seems that my #Value annotations aren't working in my LoadProperties class: package accumuloIngest; import java.io.IOException; import org.apache.accumulo.core.client.AccumuloException; import org.apache.accumulo.core.client.AccumuloSecurityException; import org.apache.accumulo.core.client.TableExistsException; import org.apache.accumulo.core.client.TableNotFoundException; import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.config.PropertyPlaceholderConfigurer; import org.springframework.context.annotation.Bean; import org.springframework.core.io.ClassPathResource; import org.springframework.core.io.Resource; public class LoadProperties { // this class defines the Spring Bean and loads the cluster properties // using the SpringFramework #Bean public static PropertyPlaceholderConfigurer props(){ PropertyPlaceholderConfigurer ppc = new PropertyPlaceholderConfigurer(); Resource[] resource = new ClassPathResource[ ] { new ClassPathResource("/EclipseProjectName/src/cluster.properties") }; ppc.setLocations(resource); ppc.setIgnoreUnresolvablePlaceholders(true); return ppc; } // Now load the properties from cluster.properties using the Spring Framework private #Value("${cluster.instance}") String instanceName; private #Value("${cluster.username}") String userName; private #Value("${cluster.password}") String password; private #Value("${cluster.zooServers}") String zooServers; private #Value("${cluster.TableName}") String tableName; private #Value("${cluster.DataFile}") String dataFile; private #Value("${cluster.DataDelimiter}") String dataDelim; private #Value("${cluster.rowCount}") int rowCount; // Getters for the other Java classes to access properties loaded by Spring public String getInstanceName() { return instanceName; } public String getUserName() { return userName; } public String getPassword() { return password; } public String getZooServers() { return zooServers; } public String getTableName() { return tableName; } public String getDataFile() { return dataFile; } public String getDataDelim() { return dataDelim; } public int getRowCount() { return rowCount; } // method to kick off the ingest of dummy data void startIngest() { Ingester ingestObject = new Ingester(); try { ingestObject.ingestData(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (TableNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (TableExistsException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (AccumuloException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (AccumuloSecurityException e) { // TODO Auto-generated catch block e.printStackTrace(); } // end of try-catch block } // end of startIngest method } // end of LoadProperties class Yet when I run MainApp.java in Eclipse the values are null when my Ingester.java class calls the getters. Here's the console output when I run MainApp.java in Eclipse: 13/09/24 14:08:24 INFO support.ClassPathXmlApplicationContext: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext#191f667c: startup date [Tue Sep 24 14:08:24 EDT 2013]; root of context hierarchy 13/09/24 14:08:24 INFO xml.XmlBeanDefinitionReader: Loading XML bean definitions from class path resource [context.xml] 13/09/24 14:08:24 INFO support.DefaultListableBeanFactory: Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory#3cdd17f5: defining beans [props]; root of factory hierarchy Printing out cluster.properties read via Spring... instanceName= null userName= null password= null zooServers= null tableName= null dataFile= null dataDelim= null rowCount= 0 Exception in thread "main" java.lang.IllegalArgumentException: argument was null:Is null- arg1? true arg2? true at org.apache.accumulo.core.util.ArgumentChecker.notNull(ArgumentChecker.java:36) at org.apache.accumulo.core.client.ZooKeeperInstance.<init>(ZooKeeperInstance.java:99) at org.apache.accumulo.core.client.ZooKeeperInstance.<init>(ZooKeeperInstance.java:85) at accumuloIngest.Ingester.ingestData(Ingester.java:65) at accumuloIngest.LoadProperties.startIngest(LoadProperties.java:69) at accumuloIngest.MainApp.main(MainApp.java:44) Am I missing a piece of the Spring framework that loads the properties in my cluster.properties file? I had tried adding #AutoWired to both my MainApp and LoadProperties java classes but that didn't seem to help.
If you're going to use #Bean, you'll need #Configuration. You shouldn't declare a xml context to include an annotation context. You also shouldn't use your #Configuration class instance as a bean. ClassPathXmlApplicationContext is no good for processing annotation based configurations. Use something like the following #Configuration #ComponentScan(basePackageClasses = LoadProperties.class) public static class Config { #Bean public static PropertyPlaceholderConfigurer props() { PropertyPlaceholderConfigurer ppc = new PropertyPlaceholderConfigurer(); Resource[] resource = new ClassPathResource[] { new ClassPathResource( "/EclipseProjectName/src/cluster.properties") }; ppc.setLocations(resource); ppc.setIgnoreUnresolvablePlaceholders(true); return ppc; } #Bean public LoadProperties loadProperties() { return new LoadProperties(); } } public static class LoadProperties { private #Value("${cluster.zooServers}") String zooServers; ... // getters and setters } public static void main(String[] args) throws Exception { AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Config.class); LoadProperties load = (LoadProperties) context.getBean(LoadProperties.class); System.out.println(load.getZooServers()); } A few things to note: In your ClassPathResource you need to specify a classpath resource. Do you really have a resource /EclipseProjectName/src/cluster.properties at the root of your classpath? I very much doubt it. In this case you won't need a #ComponentScan, but familiarize yourself with it. A PropertyPlaceholderConfigurer needs to be declared static so it can be initialized before the other #Bean declarations. You should use PropertySourcesPlaceholderConfigurer as explained in the javadoc.
Print all the Spring beans that are loaded
Is there a way to print all the spring beans that are loaded on startup?I am using Spring 2.0.
Yes, get ahold of ApplicationContext and call .getBeanDefinitionNames() You can get the context by: implementing ApplicationContextAware injecting it with #Inject / #Autowired (after 2.5) use WebApplicationContextUtils.getRequiredWebApplicationContext(..) Related: You can also detect each bean's registration by registering a BeanPostprocessor bean. It will be notified for each bean.
public class PrintBeans { #Autowired ApplicationContext applicationContext; public void printBeans() { System.out.println(Arrays.asList(applicationContext.getBeanDefinitionNames())); } }
With Spring Boot and the actuator starter <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> you can check the endpoint /beans
Print all bean names and its classes: package com.javahash.spring.controller; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationContext; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; #Controller public class HelloWorldController { #Autowired private ApplicationContext applicationContext; #RequestMapping("/hello") public String hello(#RequestParam(value="key", required=false, defaultValue="World") String name, Model model) { String[] beanNames = applicationContext.getBeanDefinitionNames(); for (String beanName : beanNames) { System.out.println(beanName + " : " + applicationContext.getBean(beanName).getClass().toString()); } model.addAttribute("name", name); return "helloworld"; } }
applicationContext.getBeanDefinitionNames() does not show the beans which are registered without BeanDefinition instance. package io.velu.core; import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; #Configuration #ComponentScan public class Core { public static void main(String[] args) { AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Core.class); String[] singletonNames = context.getDefaultListableBeanFactory().getSingletonNames(); for (String singleton : singletonNames) { System.out.println(singleton); } } } Console Output environment systemProperties systemEnvironment org.springframework.context.annotation.internalConfigurationAnnotationProcessor org.springframework.context.annotation.ConfigurationClassPostProcessor.importRegistry org.springframework.context.event.internalEventListenerProcessor org.springframework.context.event.internalEventListenerFactory org.springframework.context.annotation.internalAutowiredAnnotationProcessor org.springframework.context.annotation.internalCommonAnnotationProcessor messageSource applicationEventMulticaster lifecycleProcessor As you can see in the output, environment, systemProperties, systemEnvironment beans will not be shown using context.getBeanDefinitionNames() method. Spring Boot For spring boot web applications, all the beans can be listed using the below endpoint. #RestController #RequestMapping("/list") class ExportController { #Autowired private ApplicationContext applicationContext; #GetMapping("/beans") #ResponseStatus(value = HttpStatus.OK) String[] registeredBeans() { return printBeans(); } private String[] printBeans() { AutowireCapableBeanFactory autowireCapableBeanFactory = applicationContext.getAutowireCapableBeanFactory(); if (autowireCapableBeanFactory instanceof SingletonBeanRegistry) { String[] singletonNames = ((SingletonBeanRegistry) autowireCapableBeanFactory).getSingletonNames(); for (String singleton : singletonNames) { System.out.println(singleton); } return singletonNames; } return null; } } [ "autoConfigurationReport", "springApplicationArguments", "springBootBanner", "springBootLoggingSystem", "environment", "systemProperties", "systemEnvironment", "org.springframework.context.annotation.internalConfigurationAnnotationProcessor", "org.springframework.boot.autoconfigure.internalCachingMetadataReaderFactory", "org.springframework.boot.autoconfigure.condition.BeanTypeRegistry", "org.springframework.context.annotation.ConfigurationClassPostProcessor.importRegistry", "propertySourcesPlaceholderConfigurer", "org.springframework.boot.context.properties.ConfigurationPropertiesBindingPostProcessor.store", "preserveErrorControllerTargetClassPostProcessor", "org.springframework.context.annotation.internalAutowiredAnnotationProcessor", "org.springframework.context.annotation.internalRequiredAnnotationProcessor", "org.springframework.context.annotation.internalCommonAnnotationProcessor", "org.springframework.boot.context.properties.ConfigurationPropertiesBindingPostProcessor", "org.springframework.scheduling.annotation.ProxyAsyncConfiguration", "org.springframework.context.annotation.internalAsyncAnnotationProcessor", "methodValidationPostProcessor", "embeddedServletContainerCustomizerBeanPostProcessor", "errorPageRegistrarBeanPostProcessor", "messageSource", "applicationEventMulticaster", "org.springframework.boot.autoconfigure.web.EmbeddedServletContainerAutoConfiguration$EmbeddedTomcat", "tomcatEmbeddedServletContainerFactory", "org.springframework.boot.autoconfigure.websocket.WebSocketAutoConfiguration$TomcatWebSocketConfiguration", "websocketContainerCustomizer", "spring.http.encoding-org.springframework.boot.autoconfigure.web.HttpEncodingProperties", "org.springframework.boot.autoconfigure.web.HttpEncodingAutoConfiguration", "localeCharsetMappingsCustomizer", "org.springframework.boot.autoconfigure.web.ServerPropertiesAutoConfiguration", "serverProperties", "duplicateServerPropertiesDetector", "spring.resources-org.springframework.boot.autoconfigure.web.ResourceProperties", "org.springframework.boot.autoconfigure.web.ErrorMvcAutoConfiguration$DefaultErrorViewResolverConfiguration", "conventionErrorViewResolver", "org.springframework.boot.autoconfigure.web.ErrorMvcAutoConfiguration", "errorPageCustomizer", "servletContext", "contextParameters", "contextAttributes", "spring.mvc-org.springframework.boot.autoconfigure.web.WebMvcProperties", "spring.http.multipart-org.springframework.boot.autoconfigure.web.MultipartProperties", "org.springframework.boot.autoconfigure.web.MultipartAutoConfiguration", "multipartConfigElement", "org.springframework.boot.autoconfigure.web.DispatcherServletAutoConfiguration$DispatcherServletRegistrationConfiguration", "org.springframework.boot.autoconfigure.web.DispatcherServletAutoConfiguration$DispatcherServletConfiguration", "dispatcherServlet", "dispatcherServletRegistration", "requestContextFilter", "org.springframework.boot.autoconfigure.web.WebMvcAutoConfiguration", "hiddenHttpMethodFilter", "httpPutFormContentFilter", "characterEncodingFilter", "org.springframework.context.event.internalEventListenerProcessor", "org.springframework.context.event.internalEventListenerFactory", "reportGeneratorApplication", "exportController", "exportService", "org.springframework.boot.autoconfigure.AutoConfigurationPackages", "org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration", "org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration$Jackson2ObjectMapperBuilderCustomizerConfiguration", "spring.jackson-org.springframework.boot.autoconfigure.jackson.JacksonProperties", "standardJacksonObjectMapperBuilderCustomizer", "org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration$JacksonObjectMapperBuilderConfiguration", "org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration", "jsonComponentModule", "jacksonObjectMapperBuilder", "org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration$JacksonObjectMapperConfiguration", "jacksonObjectMapper", "org.springframework.boot.autoconfigure.websocket.WebSocketAutoConfiguration", "org.springframework.boot.autoconfigure.web.EmbeddedServletContainerAutoConfiguration", "org.springframework.boot.autoconfigure.web.DispatcherServletAutoConfiguration", "org.springframework.boot.autoconfigure.validation.ValidationAutoConfiguration", "defaultValidator", "org.springframework.boot.autoconfigure.web.ErrorMvcAutoConfiguration$WhitelabelErrorViewConfiguration", "error", "beanNameViewResolver", "errorAttributes", "basicErrorController", "org.springframework.boot.autoconfigure.web.WebMvcAutoConfiguration$EnableWebMvcConfiguration", "org.springframework.boot.autoconfigure.web.WebMvcAutoConfiguration$WebMvcAutoConfigurationAdapter", "mvcContentNegotiationManager", "org.springframework.boot.autoconfigure.web.HttpMessageConvertersAutoConfiguration$StringHttpMessageConverterConfiguration", "stringHttpMessageConverter", "org.springframework.boot.autoconfigure.web.JacksonHttpMessageConvertersConfiguration$MappingJackson2HttpMessageConverterConfiguration", "mappingJackson2HttpMessageConverter", "org.springframework.boot.autoconfigure.web.HttpMessageConvertersAutoConfiguration", "messageConverters", "mvcConversionService", "mvcValidator", "requestMappingHandlerAdapter", "mvcResourceUrlProvider", "requestMappingHandlerMapping", "mvcPathMatcher", "mvcUrlPathHelper", "viewControllerHandlerMapping", "beanNameHandlerMapping", "resourceHandlerMapping", "defaultServletHandlerMapping", "mvcUriComponentsContributor", "httpRequestHandlerAdapter", "simpleControllerHandlerAdapter", "handlerExceptionResolver", "mvcViewResolver", "org.springframework.boot.autoconfigure.web.WebMvcAutoConfiguration$WebMvcAutoConfigurationAdapter$FaviconConfiguration", "faviconRequestHandler", "faviconHandlerMapping", "defaultViewResolver", "viewResolver", "welcomePageHandlerMapping", "org.springframework.boot.autoconfigure.jmx.JmxAutoConfiguration", "objectNamingStrategy", "mbeanServer", "mbeanExporter", "org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration", "springApplicationAdminRegistrar", "org.springframework.boot.autoconfigure.context.ConfigurationPropertiesAutoConfiguration", "org.springframework.boot.autoconfigure.web.JacksonHttpMessageConvertersConfiguration", "spring.info-org.springframework.boot.autoconfigure.info.ProjectInfoProperties", "org.springframework.boot.autoconfigure.info.ProjectInfoAutoConfiguration", "multipartResolver", "org.springframework.boot.autoconfigure.web.WebClientAutoConfiguration$RestTemplateConfiguration", "restTemplateBuilder", "org.springframework.boot.autoconfigure.web.WebClientAutoConfiguration", "spring.devtools-org.springframework.boot.devtools.autoconfigure.DevToolsProperties", "org.springframework.boot.devtools.autoconfigure.LocalDevToolsAutoConfiguration$RestartConfiguration", "fileSystemWatcherFactory", "classPathRestartStrategy", "classPathFileSystemWatcher", "hateoasObjenesisCacheDisabler", "org.springframework.boot.devtools.autoconfigure.LocalDevToolsAutoConfiguration$LiveReloadConfiguration$LiveReloadServerConfiguration", "org.springframework.boot.devtools.autoconfigure.LocalDevToolsAutoConfiguration$LiveReloadConfiguration", "optionalLiveReloadServer", "org.springframework.boot.devtools.autoconfigure.LocalDevToolsAutoConfiguration", "lifecycleProcessor" ]
You could try calling org.springframework.beans.factory.ListableBeanFactory.getBeansOfType(Object.class) Or turn on debug logging for org.springframework. (In spring boot, that's using a parameter --logging.level.org.springframework=DEBUG)
Here is another way to print all the bean names from the spring application context: import java.util.Arrays; import java.util.concurrent.atomic.AtomicInteger; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.context.ConfigurableApplicationContext; /*********************************************************************************************************** * Java File: MainApplication.java * Description: Main class to run the application. * ***********************************************************************************************************/ #SpringBootApplication public class MainApplication { private static final Logger logger = LogManager.getLogger(MainApplication.class); public static void main(String[] args) { final ConfigurableApplicationContext context = SpringApplication.run(MainApplication.class, args); final AtomicInteger counter = new AtomicInteger(0); logger.info("**************** START: Total Bean Objects: {} ******************", context.getBeanDefinitionCount()); Arrays.asList(context.getBeanDefinitionNames()) .forEach(beanName -> { logger.info("{}) Bean Name: {} ", counter.incrementAndGet(), beanName); }); logger.info("**************** END: Total Bean: {} ******************", context.getBeanDefinitionCount()); } } Sample Output: 2019-11-27 20:08:02.821 INFO [main] [c.c.a.MainApplication:18] - **************** START: Total Bean Objects: 564 ****************** ........................... 2019-11-27 20:08:02.821 INFO [main] [c.c.a.MainApplication:22] - 460) Bean Name: mvcPathMatcher 2019-11-27 20:08:02.821 INFO [main] [c.c.a.MainApplication:22] - 461) Bean Name: mvcUrlPathHelper 2019-11-27 20:08:02.821 INFO [main] [c.c.a.MainApplication:22] - 462) Bean Name: viewControllerHandlerMapping 2019-11-27 20:08:02.821 INFO [main] [c.c.a.MainApplication:22] - 463) Bean Name: beanNameHandlerMapping 2019-11-27 20:08:02.821 INFO [main] [c.c.a.MainApplication:22] - 464) Bean Name: resourceHandlerMapping ........................... 2019-11-27 20:08:02.821 INFO [main] [c.c.a.MainApplication:25] - **************** END: Total Bean: 564 ******************
Using spring-boot-starter-actuator you can easily access all bean. Here is the setup process: Add dependency into gradle: Add bellow into gradle file: compile("org.springframework.boot:spring-boot-starter-actuator") Enable security on application.properties: Add management.security.enabled=false into your application.property file call /beans endpoint: After that setup spring will enable some metrics related endpoints. One of its endpoint is /beans After calling this endpoints it will provide a json file that contains all of your bean including it's dependency and scope. Here is an example json file: [{"context":"application:8442","parent":null,"beans":[{"bean":"beanName","aliases":[],"scope":"singleton","type":"packageName$$4b46c703","resource":"null","dependencies":["environment","beanName1","beanName2"]},{"bean":"org.springframework.boot.autoconfigure.internalCachingMetadataReaderFactory","aliases":[],"scope":"singleton","type":"org.springframework.core.type.classreading.CachingMetadataReaderFactory","resource":"null","dependencies":[]}] For more info visit bellow links: Building a RESTful Web Service with Spring Boot Actuator Spring Boot Actuator: Health check, Auditing, Metrics gathering Spring Boot Actuator: Production-ready features Hope this will help you. Thanks :)