This question already has answers here:
Why is my Spring #Autowired field null?
(21 answers)
Closed 6 years ago.
I am a newbie to Spring and I am trying to load properties file using Spring framework, I am able to successfully load all the properties from junit test but when I am trying to implement the unit test as function it throws NPE-
my junit class (which is working as expected)
#RunWith(SpringJUnit4ClassRunner.class)
#ActiveProfiles(profiles = "test")
#ContextConfiguration("classpath:spring/xml-config-context.xml")
public class GlueTestPropertiesTest2 extends TestCase {
#Autowired
GenericEnv env;
#Autowired
WebPropertiesLoader wpl;
#Test
public void testAppProperties() {
System.out.println("Running MiniConfigSpringPropertiesTest ...");
System.out.println("Environment : " + env.toString());
System.out.println("Database Properties: " + wpl.toString());
}
}
My implementation class (Which is exhibiting NPE) :
#ActiveProfiles(profiles = "test")
#ContextConfiguration("classpath:spring/xml-config-context.xml")
public class GlueTestProperties {
#Autowired
GenericEnv env;
#Autowired
WebPropertiesLoader wpl;
public static void main(String[] args) {
GlueTestProperties gp = new GlueTestProperties();
gp.callme();
}
private void callme(){
System.out.println("Running ConfigSpringPropertiesTest ...");
System.out.println("Environment : " + env.toString());
System.out.println("Database Properties: " + wpl.toString());
}
}
WebPropertiesLoader bean :
#Component
public class WebPropertiesLoader {
#Value("${bank.ease.login.url}")
public String easeLoginUrl;
#Value("${bank.browser.name}")
public String browserName;
#Value("${bank.browser.version}")
public String browserVersion;
#Value("${webdriver.chrome.driver}")
public String chromeDriver;
#Value("${webdriver.ie.driver}")
public String ieDriver;
#Value("${bank.web.feature.location}")
public String webFeatureLocation;
#Value("${bank.web.test.location}")
public String webTestLocation;
#Value("${bank.event.log}")
public String eventLog;
#Value("${bank.epoxy.backend}")
public String epoxyBackend;
#Value("${bank.epoxy.host}")
public String epoxyHost;
#Value("${bank.epoxy.port}")
public String epoxyPort;
#Value("${bank.epoxy.debug}")
public String epoxyDebug;
#Value("${bank.epoxy.implicitWait}")
public String epoxyImplicitWait;
#Value("${bank.epoxy.timeout}")
public String epoxyTimeOut;
#Value("${bank.epoxy.default.url}")
public String epoxyDefaultURL;
#Value("${bank.sassy.url}")
public String sassyUrl;
#Value("${bank.transite.url}")
public String transiteUrl;
#Value("${bank.transite.login.url}")
public String transiteLoginUrl;
public String getBrowserName() {
return browserName;
}
public String getBrowserVersion() {
return browserVersion;
}
public String getChromeDriver() {
return chromeDriver;
}
public String getEpoxyDefaultURL() {
return epoxyDefaultURL;
}
public String getSassyUrl() {
return sassyUrl;
}
public String getTransiteUrl() {
return transiteUrl;
}
public String getTransiteLoginUrl() {
return transiteLoginUrl;
}
public String getIeDriver() {
return ieDriver;
}
public String getWebFeatureLocation() {
return webFeatureLocation;
}
public String getWebTestLocation() {
return webTestLocation;
}
public String getEventLog() {
return eventLog;
}
public String getEpoxyBackend() {
return epoxyBackend;
}
public String getEpoxyHost() {
return epoxyHost;
}
public String getEpoxyPort() {
return epoxyPort;
}
public String getEpoxyDebug() {
return epoxyDebug;
}
public String getEpoxyImplicitWait() {
return epoxyImplicitWait;
}
public String getEpoxyTimeOut() {
return epoxyTimeOut;
}
public String getEaseLoginUrl() {
return easeLoginUrl;
}
#Override
public String toString() {
return "Ease application Default Properties [browserName=" + browserName + ", browserVersion=" + browserVersion
+ ", chromeDriver=" + chromeDriver + ", ieDriver=" + ieDriver + ", webFeatureLocation="
+ webFeatureLocation + ", webTestLocation=" + webTestLocation + ", eventLog=" + eventLog
+ ", epoxyBackend=" + epoxyBackend + ", epoxyHost=" + epoxyHost + ", epoxyPort=" + epoxyPort
+ ", epoxyDebug=" + epoxyDebug + ", epoxyImplicitWait=" + epoxyImplicitWait + ", epoxyTimeOut="
+ epoxyTimeOut + ", epoxyDefaultURL=" + epoxyDefaultURL + ", easeLoginUrl=" + easeLoginUrl + "]";
}
}
Test env bean :
#Component
public class TestEnv implements GenericEnv {
private String envName = "test";
#Value("${profile.name}")
private String profileName;
public String getEnvName() {
return envName;
}
public void setEnvName(String envName) {
this.envName = envName;
}
public String getProfileName() {
return profileName;
}
public void setProfileName(String profileName) {
this.profileName = profileName;
}
#Override
public String toString() {
return "TestEnv [envName=" + envName + ", profileName=" + profileName
+ "]";
}
}
Context xml used :
?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://cxf.apache.org/core http://cxf.apache.org/schemas/core.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<!-- scans for annotated classes in the com.company package -->
<context:component-scan base-package="com.glue.commons" />
<!-- enables annotation based configuration -->
<!-- <context:annotation-config /> -->
<beans profile="dev">
<!-- allows for ${} replacement in the spring xml configuration from the
application-default.properties, application-dev files on the classpath -->
<context:property-placeholder
location="classpath:properties/application-web-default.properties, classpath:properties/application-web-dev.properties"
ignore-unresolvable="true" />
<!-- scans for annotated classes in the com.env.dev package -->
<context:component-scan base-package="com.glue.env.dev" />
</beans>
<beans profile="test">
<!-- allows for ${} replacement in the spring xml configuration from the
application-default.properties, application-test files on the classpath -->
<context:property-placeholder
location="classpath:properties/application-web-default.properties, classpath:properties/application-web-qa2.properties"
ignore-unresolvable="true" />
<!-- scans for annotated classes in the com.env.test package -->
<context:component-scan base-package="com.glue.env.test" />
</beans>
<beans profile="prod">
<!-- allows for ${} replacement in the spring xml configuration from the
application-default.properties, application-prod files on the classpath -->
<context:property-placeholder
location="classpath:properties/application-web-default.properties, classpath:properties/application-web-prod.properties"
ignore-unresolvable="true" />
<!-- scans for annotated classes in the com.env.prod package -->
<context:component-scan base-package="com.glue.env.prod" />
</beans>
<beans profile="dev">
<!-- allows for ${} replacement in the spring xml configuration from the
application-default.properties, application-dev files on the classpath -->
<context:property-placeholder
location="classpath:properties/application-api-default.properties, classpath:properties/application-api-dev.properties"
ignore-unresolvable="true" />
<!-- scans for annotated classes in the com.env.dev package -->
<context:component-scan base-package="com.glue.env.dev" />
</beans>
<beans profile="test">
<!-- allows for ${} replacement in the spring xml configuration from the
application-default.properties, application-test files on the classpath -->
<context:property-placeholder
location="classpath:properties/application-api-default.properties, classpath:properties/application-api-qa2.properties"
ignore-unresolvable="true" />
<!-- scans for annotated classes in the com.env.test package -->
<context:component-scan base-package="com.glue.env.test" />
</beans>
<beans profile="prod">
<!-- allows for ${} replacement in the spring xml configuration from the
application-default.properties, application-prod files on the classpath -->
<context:property-placeholder
location="classpath:properties/application-api-default.properties, classpath:properties/application-api-prod.properties"
ignore-unresolvable="true" />
<!-- scans for annotated classes in the com.env.prod package -->
<context:component-scan base-package="com.glue.env.prod" />
</beans>
Thanks in advance, please forgive me if I've made some silly mistake, but I need your help.
If you use the main method to create it then spring won't know anything about this class so it won't autowire any classes - you get nulls in all fields annotated with #Autowired.
Your JUnit is working correctly because it is instantiated with spring aware junit runner.
I am able to get the properties to load. Issue was that as #krzyk pointed out my implementation class was not spring aware hence it was not able to load the profile from my context xml and to make it aware of my profile bean I had to pass vm argument through my main class, following code change and approach helped me :
my implementation class look like this now:
#ContextConfiguration("classpath:spring/xml-config-context.xml")
public class GlueTestProperties {
private GlueTestProperties() {
}
private static ApplicationContext context;
public static GenericEnv getEnv() {
return getContext().getBean(TestEnv.class);
}
public static WebPropertiesLoader getWebProperties() {
return getContext().getBean(WebPropertiesLoader.class);
}
public static ApiPropertiesLoader getApiProperties() {
return getContext().getBean(ApiPropertiesLoader.class);
}
private static ApplicationContext getContext() {
if (null == context) {
init();
}
return context;
}
private static synchronized void init() {
context = new ClassPathXmlApplicationContext("spring/xml-config-context.xml");
}
}
I am passing following as vm argument : -Dspring.profiles.active=test
Or second approach would be you have to take out
<context:property-placeholder
location="classpath:properties/application-web-default.properties, classpath:properties/application-web-qa2.properties"
ignore-unresolvable="true" />
from your <bean/> and place it out side so that it will be visible for main class and you do not have to pass vm arguments here.
Related
Here is the structure of sample Spring application
src
main
my.example
- MyBean.java
- AppMain.java
resources
- applicationContext.xml
- some.properties
applicationContext.xml
<beans ...>
<context:property-placeholder location="classpath:some.properties"/>
<bean id="a" class="my.example.MyBean"/>
</beans>
some.properties
myprop=something
AppMain.java
public class AppMain {
public static void main(String[] args) {
var context = new ClassPathXmlApplicationContext();
context.setConfigLocations("classpath:applicationContext.xml");
context.refresh();
var bean = context.getBean("a");
println(bean); // available
ConfigurableEnvironment environment = context.getEnvironment();
String javaHome = environment.getProperty("java.home");
String myprop = environment.getProperty("myprop");
println(environment.getPropertySources());
println("javaHome is " + javaHome); // ok
println("myprop is " + myprop); // is null
}
}
Output:
my.example.MyBean#cecf639
[PropertiesPropertySource {name='systemProperties'}, SystemEnvironmentPropertySource {name='systemEnvironment'}]
javahome is [/mypath/to/java/17.0.5-zulu]
myprop is [null]
As the output shows the property sources do not contains some.properties file, and hence myprop is null. At the same time the bean MyBean is available, which means applicationContext.xml was processed.
Why <context:property-placeholder ...> had no effect?
How to add some.properties file to the context, and get correct myprop value?
I have an app that uses jars from other apps. My application which is called com_Streams_H2O_ML.java uses HazelcastInsance.
package com.escomled.machinelearning.ml;
import static com.com.machinelearning.ml.PropertiesGenerator.getProperty;
import java.io.File;
import java.util.Properties;
import org.apache.kafka.common.serialization.Serdes;
import org.apache.kafka.streams.KafkaStreams;
import org.apache.kafka.streams.StreamsConfig;
import org.apache.kafka.streams.kstream.KStream;
import org.apache.kafka.streams.kstream.KStreamBuilder;
import org.springframework.stereotype.Repository;
import com.com.blackboard.Blackboard;
import com.com.machinelearning.ml.Escomled_Streams_H2O_ML;
import com.com.machinelearning.startmap.ContextHolder;
import com.hazelcast.core.HazelcastInstance;
import com.hazelcast.core.IMap;
import hex.genmodel.easy.EasyPredictModelWrapper;
import hex.genmodel.easy.RowData;
import hex.genmodel.easy.exception.PredictException;
import hex.genmodel.easy.prediction.RegressionModelPrediction;
/**
*
*
* Creates a new Kafka Streams application for prediction of watts The
* application uses the GBM model "comPOJO" (built with H2O.ai and python
* application) to infer messages sent to Kafka topic "comInputTopic". The
* outcome of model inference is sent to Kafka topic "comOutputTopic".
*
*/
public class com_Streams_H2O_ML {
// Name of the generated H2O model
private static String modelClassName = getProperty("pojoFullName");
// Prediction Value
private static double watts = 0;
public static boolean isNumeric(String str) {
return str.matches("-?\\d+(\\.\\d+)?"); // match a number with optional '-' and decimal.
}
public static void main(final String[] args) throws Exception {
System.out.println(new File(".").getAbsolutePath());
// Create H2O object (see gbm_pojo_test.java)
hex.genmodel.GenModel rawModel;
rawModel = (hex.genmodel.GenModel) Class.forName(modelClassName).newInstance();
EasyPredictModelWrapper model = new EasyPredictModelWrapper(
new EasyPredictModelWrapper.Config().setModel(rawModel).setConvertUnknownCategoricalLevelsToNa(false));
HazelcastInstance instance = ((Blackboard) ContextHolder.getContext().getBean("blackboard")).getHazelcastInstance();
IMap<String, String> dimmingMap = instance.getMap("dim_board_map");
// Configure Kafka Streams Application
final String bootstrapServers = args.length > 0 ? args[0] : getProperty("bootstrapServers");
final Properties streamsConfiguration = new Properties();
// Give the Streams application a unique name. The name must be unique
// in the Kafka cluster
// against which the application is run.
streamsConfiguration.put(StreamsConfig.APPLICATION_ID_CONFIG, "Escomled_Streams_ML");
// Where to find Kafka broker(s).
streamsConfiguration.put(StreamsConfig.BOOTSTRAP_SERVERS_CONFIG, bootstrapServers);
// Specify default (de)serializers for record keys and for record
// values.
streamsConfiguration.put(StreamsConfig.KEY_SERDE_CLASS_CONFIG, Serdes.String().getClass().getName());
streamsConfiguration.put(StreamsConfig.VALUE_SERDE_CLASS_CONFIG, Serdes.String().getClass().getName());
// For illustrative purposes we disable record caches
streamsConfiguration.put(StreamsConfig.CACHE_MAX_BYTES_BUFFERING_CONFIG, 0);
// In the subsequent lines we define the processing topology of the
// Streams application.
final KStreamBuilder builder = new KStreamBuilder();
// Construct a `KStream` from the input topic "EscomledInputTopic", where
// message values
// represent lines of text (for the sake of this example, we ignore
// whatever may be stored
// in the message keys).
String inputTopic = getProperty("inputTopic");
final KStream<String, String> predictionInput = builder.stream(inputTopic);
// Stream Processor (in this case 'foreach' to add custom logic, i.e. apply the
// analytic model)
predictionInput.foreach((key, value) -> {
String[] values = value.split(",");
System.out.println("Key " + key);
System.out.println("Value " + value);
if (value != null && !value.equals("") && isNumeric(value)) {
RowData row = new RowData();
row.put("Board Number", key);
row.put("Dimming", value);
RegressionModelPrediction p = null;
try {
p = model.predictRegression(row);
watts = p.value;
System.out.println("Prediction for " + key + "/" + value + "% :" + watts + "W");
} catch (PredictException e) {
e.printStackTrace();
}
dimmingMap.remove(key);
} else {
System.out.println("ENTER CORRECT VALUES");
}
});
// Transform message: Add prediction information
KStream<String, Object> transformedMessage = predictionInput.mapValues(value -> value + ", " + watts);
// Send prediction information to Output Topic
String outputTopic = getProperty("outputTopic");
transformedMessage.to(outputTopic);
// Start Kafka Streams Application to process new incoming messages from Input
// Topic
final KafkaStreams streams = new KafkaStreams(builder, streamsConfiguration);
streams.cleanUp();
streams.start();
// Add shutdown hook to respond to SIGTERM and gracefully close Kafka
// Streams
Runtime.getRuntime().addShutdownHook(new Thread(streams::close));
}
}
My appContext.xml contains:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:hz="http://www.hazelcast.com/schema/spring"
xmlns:task="http://www.springframework.org/schema/task" xmlns:context="http://www.springframework.org/schema/context"
xmlns:int="http://www.springframework.org/schema/integration"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.hazelcast.com/schema/spring http://www.hazelcast.com/schema/spring/hazelcast-spring-3.2.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-2.5.xsd
http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task.xsd ">
<context:annotation-config />
<context:component-scan base-package="com.escomled" />
<context:component-scan base-package="com.escomled.*" />
<import resource="classpath*:config/blackBoard.xml" />
<task:annotation-driven />
<bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<list>
<value>file:///home/escomled/escomled_server/config/escomled.properties</value>
</list>
</property>
</bean>
<bean id="reportJdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource" />
</bean>
<bean id="blackboard" class="com.escomled.blackboard.impl.BlackboardImpl">
<property name="hazelcastInstance" ref="hazelcastClient" />
</bean>
</beans>
I also have an app called escomled_common which contains com.escomled.blackboard.impl package. In that package I implement blackboard with a class called BlackboardImpl.java
BlackboardImpl.java content
...#Component("blackboard")
public class BlackboardImpl implements Blackboard {
private HazelcastInstance hazelcastInstance;
#Override
public HazelcastInstance getHazelcastInstance() {
return hazelcastInstance;
}
public void setHazelcastInstance(HazelcastInstance hazelcastInstance) {
this.hazelcastInstance = hazelcastInstance;
}...
I get an error
Exception in thread "main" org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'blackboard' defined in class path resource [appContext.xml]: Cannot resolve reference to bean 'instance' while setting bean property 'hazelcastInstance'; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'instance' is defined
Someone help ?
I'm in the process of upgrading the spring framework version used in our webapp from 3.1.4 to 4.1.8. With the new Spring version, A few of our unit tests are failing because #Autowired is no longer working. This is one of the failing tests:
#ContextConfiguration(locations={"/math-application-context.xml"})
public class MathematicaMathServiceTest extends JavaMathServiceTest{
#Autowired
private KernelLinkPool mathematicalKernelPool;
protected static String originalServiceType = System.getProperty("calculation.math.service.type");
#AfterClass
public static void unsetMathServiceType(){
System.clearProperty("calculation.math.service.type");
}
#BeforeClass
public static void setMathServiceType(){
System.setProperty("calculation.math.service.type","Mathematica");
}
#Test
public void testMathematicaService() throws Exception{
try {
acquireKernelAndExecute(0);
Assert.assertEquals(0, mathematicalKernelPool.getBorrowingThreadsCount());
} catch(UnsatisfiedLinkError e) {
System.out.println("Mathematica not installed. Skipping test");
}catch(Exception ex){
if (!ExceptionFormatter.hasCause(ex, MathServiceNotConfiguredException.class)){throw ex;}
if (System.getProperty(MathService.SERVICE_CONFIGURED_SYSTEM_VARIABLE) != null){
throw ex;
}
logger.error("Cannot execute test. Math service is not configured");
}
}
}
This is the KernelLinkPool class:
public class KernelLinkPool extends GenericObjectPool implements InitializingBean{
private static final int RETRY_TIMEOUT_MS = 5000;
private static final long STARTUP_WAIT_TIME_MS = 10000;
private boolean mathematicaConfigured = true;
private PoolableObjectFactory factory;
// ensures that multiple requests from the same thread will be given the same KernelLink object
private static ThreadLocal<KernelLink> threadBoundKernel = new ThreadLocal<KernelLink>();
// holds the number of requests issued on each thread
private static ThreadLocal<Integer> callDepth = new ThreadLocal<Integer>();
private long maxBorrowWait;
private Integer maxKernels;
private boolean releaseLicenseOnReturn;
private Logger logger = LoggerFactory.getLogger(this.getClass());
// (used only for unit testing at this point)
private Map<String,Integer> borrowingThreads = new ConcurrentHashMap<String,Integer>();
public KernelLinkPool(PoolableObjectFactory factory) {
super(factory);
this.factory = factory;
this.setMaxWait(maxBorrowWait);
}
#Override
public Object borrowObject() throws Exception{
return borrowObject(this.maxBorrowWait);
}
public Object borrowObject(long waitTime) throws Exception {
long starttime = System.currentTimeMillis();
if (!mathematicaConfigured){
throw new MathServiceNotConfiguredException();
}
try{
if (callDepth.get() == null){
callDepth.set(1);
}else{
callDepth.set(callDepth.get()+1);
}
KernelLink link = null;
if (threadBoundKernel.get() != null){
link = threadBoundKernel.get();
}else{
//obtain kernelLink from object pool
//retry when borrowObject fail until
//maxBorrowWait is reached
while(true){
try{
logger.debug("Borrowing MathKernel from object pool");
link = (KernelLink) super.borrowObject();
break;
}catch(KernelLinkCreationException ex){
long timeElapsed = System.currentTimeMillis() - starttime;
logger.info("Failed to borrow MathKernel. Time elapsed [" + timeElapsed + "] ms", ex);
if(timeElapsed >= waitTime){
logger.info("Retry timeout reached");
throw ex;
}
Thread.sleep(RETRY_TIMEOUT_MS);
}
}
logger.debug("borrowed [" + link + "]");
threadBoundKernel.set(link);
}
borrowingThreads.put(Thread.currentThread().getName(),callDepth.get());
return link;
}catch(Exception ex){
logger.error("Failed to acquire Mathematica kernel. Borrowing threads [" + borrowingThreads + "]");
throw ex;
}
}
public void returnObject(Object obj) throws Exception {
callDepth.set(callDepth.get()-1);
if (callDepth.get() <= 0){
threadBoundKernel.set(null);
borrowingThreads.remove(Thread.currentThread().getName());
if (releaseLicenseOnReturn){
// will destroy obj
super.invalidateObject(obj);
}
else{
// will park obj in the pool of idle objects
super.returnObject(obj);
}
}else{
borrowingThreads.put(Thread.currentThread().getName(),callDepth.get());
}
}
#Override
public void afterPropertiesSet() throws Exception {
try{
if (maxKernels == 0){
List<KernelLink> links = new ArrayList<KernelLink>();
while (true){
try{
links.add((KernelLink)factory.makeObject());
}catch(KernelLinkCreationException ex){
break;
}
}
if(links.isEmpty()){
logger.warn("No available Mathematica license!");
mathematicaConfigured = false;
return;
}
for (KernelLink link : links){
factory.destroyObject(link);
}
logger.info("Detected number of available Mathematica license = [" + links.size() + "]");
setMaxActive(links.size());
setMaxIdle(links.size());
}else{
if(maxKernels < 0){
logger.info("Set number of Mathematica license to no limit");
}else{
logger.info("Set number of Mathematica license to [" + maxKernels + "]");
}
setMaxActive(maxKernels);
setMaxIdle(maxKernels);
}
Object ob = borrowObject(STARTUP_WAIT_TIME_MS);
returnObject(ob);
mathematicaConfigured = true;
}catch(Throwable ex){
logger.warn("Mathematica kernel pool could not be configured: ", ex.getMessage());
mathematicaConfigured = false;
}
}
public int getBorrowingThreadsCount() {
return borrowingThreads.size();
}
public Integer getMaxKernels() {
return maxKernels;
}
public void setMaxKernels(Integer maxKernels) {
this.maxKernels = maxKernels;
}
public boolean isMathematicaConfigured(){
return mathematicaConfigured;
}
public boolean isReleaseLicenseOnReturn() {
return releaseLicenseOnReturn;
}
public void setReleaseLicenseOnReturn(boolean releaseLicenseOnReturn) {
this.releaseLicenseOnReturn = releaseLicenseOnReturn;
}
public long getMaxBorrowWait() {
return maxBorrowWait;
}
public void setMaxBorrowWait(long maxBorrowWait) {
this.maxBorrowWait = maxBorrowWait;
}
}
The tests are failing with this exception:
org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [com.etse.math.wolfram.KernelLinkPool] 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)}
This is the math-application-context 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-3.1.xsd">
<beans profile="unitTest,integratedTest,activeServer">
<bean class="org.springframework.jmx.export.MBeanExporter"
lazy-init="false">
<property name="registrationBehaviorName" value="REGISTRATION_IGNORE_EXISTING" />
<property name="beans">
<map>
<entry key="etse.math:name=MathematicalKernelFactory"
value-ref="mathematicalKernelFactory" />
<entry key="etse.math:name=MathematicalKernelPool" value-ref="mathematicalKernelPool" />
</map>
</property>
</bean>
<bean id="mathService" class="com.etse.math.MathServiceFactoryBean">
<property name="mathServiceType" value="${calculation.math.service.type}"/>
<property name="mathematicaService" ref="mathematicaService"/>
</bean>
<bean id="mathematicaService" class="com.etse.math.wolfram.MathematicaService">
<property name="kernelPool" ref="mathematicalKernelPool" />
<property name="minParallelizationSize" value="${calculation.mathematica.kernel.parallel.batch.size}" />
</bean>
<bean id="mathematicalKernelPool" class="com.etse.math.wolfram.KernelLinkPool"
destroy-method="close">
<constructor-arg ref="mathematicalKernelFactory" />
<property name="maxKernels" value="${calculation.mathematica.max.kernels}" />
<property name="maxBorrowWait"
value="${calculation.mathematica.kernel.borrow.max.wait}" />
<property name="releaseLicenseOnReturn"
value="${calculation.mathematica.kernel.release.license.on.return}" />
</bean>
<bean id="mathematicalKernelFactory" class="com.etse.math.wolfram.KernelLinkFactory">
<property name="debugPackets" value="false" />
<property name="linkMode" value="launch" />
<property name="mathematicaKernelLocation" value="${calculation.mathematica.kernel.location}" />
<property name="mathematicaLibraryLocation" value="${calculation.mathematica.library.location}" />
<property name="mathematicaAddOnsDirectory" value="${calculation.mathematica.addons.directory}" />
<property name="linkProtocol" value="sharedMemory" />
</bean>
</beans>
<beans profile="passiveServer,thickClient,tools">
<bean id="mathService" class="com.etse.math.DummyMathService"/>
</beans>
I also tried using the application context to load the bean, but that failed with the following exception:
org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'mathematicalKernelPool' is defined
If I remove the autowired field, the test fails with a NoSuchBeanDefinitionException for another bean (mathService) that is loaded via the application context in a super class. So it appears that the application context from math-application-context is not loaded for some reason. Any idea of what could be happening here? Thank you.
UPDATE:
I took a look at the beans defined in the application context and confirmed that none of the beans defined in math-application-context are present. The application context contains only beans defined in another context file loaded by the super class. Why would it fail to load math-application-context?
At this point I would honestly get rid of the XML config and go total annotation/code based. Create a Config class and have it create any beans you need to be autowired.
It was a profile issue. The super class to the test was using:
#ProfileValueSourceConfiguration(TestProfileValueSource.class)
to set the profile, but it was not working. After removing that annotation I added:
#ActiveProfiles(resolver=TestProfileValueSource.class) and now its working again.
The following managed operation exists in the project:
#ManagedOperation(description = "Some description")
#ManagedOperationParameters({
#ManagedOperationParameter(name = "key", description = "Some description"),
})
public void foo(String key) {
// some logic
}
Also there is a property which can be used in Spring context by surrounding it with dollar sign and square brackets:
"${some.property.key}"
Is it possible to use the value of aforementioned property key in the managed operation annotation description? Something like:
#ManagedOperationParameter(name = "key",
description = "Some description, please note that the key is ${some.property.key}")
Not out-of-the-box, but it's pretty easy to customize...
public class CustomAttributeSource extends AnnotationJmxAttributeSource implements EmbeddedValueResolverAware {
private StringValueResolver embeddedValueResolver;
#Override
public void setEmbeddedValueResolver(StringValueResolver resolver) {
this.embeddedValueResolver = resolver;
}
#Override
public ManagedAttribute getManagedAttribute(Method method) throws InvalidMetadataException {
ManagedAttribute managedAttribute = super.getManagedAttribute(method);
if (this.embeddedValueResolver != null) {
managedAttribute
.setDescription(this.embeddedValueResolver.resolveStringValue(managedAttribute.getDescription()));
}
return managedAttribute;
}
#Override
public ManagedOperation getManagedOperation(Method method) throws InvalidMetadataException {
ManagedOperation managedOperation = super.getManagedOperation(method);
if (this.embeddedValueResolver != null) {
managedOperation
.setDescription(this.embeddedValueResolver.resolveStringValue(managedOperation.getDescription()));
}
return managedOperation;
}
}
Then...
<bean class="org.springframework.jmx.export.annotation.AnnotationMBeanExporter">
<property name="assembler">
<bean class="org.springframework.jmx.export.assembler.MetadataMBeanInfoAssembler">
<property name="attributeSource">
<bean class="foo.CustomAttributeSource" />
</property>
</bean>
</property>
</bean>
I have the following in my beans spring XML configuration file. here they are trying to get the password from a properties file run time and decrypt the password by calling the class "SpringPwdDecrypterUtil" which extends spring FactoryBean.
Question: in properties file where they mentioned with user and password. But the password is decrypted one which will be decrpted by the below configuration. I want to know how they(existing prod applicaiton) would have generated the password(decrpyted) and placed in the text file !
bean.xml
<property name="password">
<bean class="com.cname.SpringPwdDecrypterUtil">
<property name="password">
<value>${db.password}</value>
</property>
</bean>
</property>
--SpringPwdDecrypterUtil.java
package com.cname;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.FactoryBean;
public class SpringPwdDecrypterUtil
implements FactoryBean
{
private String password = null;
private String key = null;
public void setPassword(String password) {
this.password = password;
}
public void setKey(String key) {
this.key = key;
}
public Object getObject() {
if (StringUtils.isNotEmpty(this.key)) {
return CryptoUtils.decryptAndEncodeBase64(this.key, this.password);
}
return CryptoUtils.decryptAndEncodeBase64(this.password);
}
public Class getObjectType() {
return String.class;
}
public boolean isSingleton() {
return true;
}
}