instantiating spring bean outside the container (for testing) - java

I have following in my applicaionContext.xml
<bean id="IbatisDataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="oracle.jdbc.OracleDriver"/>
<property name="url" value="jdbc:oracle:thin:#123.210.85.56:1522:ORCL"/>
<property name="username" value="mydb"/>
<property name="password" value="mydbpwd"/>
</bean>
<bean id="myMapClient" class="org.springframework.orm.ibatis.SqlMapClientFactoryBean">
<property name="configLocation" value="classpath:sql-map-config-oracle.xml"/>
<property name="dataSource" ref="IbatisDataSource"/>
</bean>
then in my code I have:
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
SqlMapClient sqlclient = (SqlMapClient) ctx.getBean("myMapClient");
doing this gives me the following error:
Error creating bean with name
'myMapClient' defined in class
path resource
[applicationContext.xml]: Invocation
of init method failed; nested
exception is
java.lang.NoClassDefFoundError:
com/iplanet/ias/admin/common/ASException
I don't understand why is it looking for that class? I am trying to do everything outside the container. So it should not even be looking for that class...but nonetheless just to make it work I tried looking for class called ASException so I could put it on the classpath but no where can I find ASException class.
Any pointers?
Images of stack trace and my compile test / run test libs
Edit
Solution:
Even though I thought everything was outside the container...there was ONE thing that was not outside the container.
Notice the property configLocation:
<property name="configLocation" value="classpath:sql-map-config-oracle.xml"/>
actual content of sql-map-config-oracle.xml is
<sqlMapConfig>
<settings enhancementEnabled="true" useStatementNamespaces="true" />
<transactionManager type="JDBC">
<dataSource type="JNDI">
<property name="DataSource" value="my/jndi/mydb" />
</dataSource>
</transactionManager>
<sqlMap resource="somemapping.xml"/>
</sqlMapConfig>
JNDI stuff does not need to be there!
sql-map-config-oracle.xml should simply be:
<sqlMapConfig>
<settings enhancementEnabled="true" useStatementNamespaces="true" />
<sqlMap resource="somemapping.xml"/>
</sqlMapConfig>

You definitely have a runtime dependency issue as #Cletus said org.springframework.orm.ibatis.SqlMapClientFactoryBean was compiled with com.iplanet.ias.admin.common.ASException but now you don't have it in your classpath -- Spring can't find it. You should Look at the source for SqlMapClientFactoryBean to see where ASException is called -- Spring should have a dist with all it's dependencies in it, you can also look in there when doing your investigation.

This class was found during compilation but not during running:
com/iplanet/ias/admin/common/ASException
So when you're running the program, it can't seem to find this class, which belongs to the Sun app or portal server that you're using. In short: it's a classpath error.

Related

Spring Data Context - lookup placeholder variables from Java map, not properties file

Currently in my data context XML file, it's looking up values to substitute from a application.properties file:
<bean id="applicationProperties" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer" lazy-init="default">
<property name="location" value="classpath:application.properties" />
</bean>
<bean id="appleDataSource" class="org.apache.commons.dbcp2.BasicDataSource">
<property name="url" value="${apple.url}" />
</bean>
I'd like to change this from being looked up from the application.properties file, to being read out of a Properties/Map object.
This is because the configuration could come from more than one place (i.e. not just the classpath), and this logic is already implemented in my application.
I've seen MapPropertySource but I think while that can be done when the bean is configured in Java, I'm not sure this logic can be implemented when working with the XML file alone?

Why error No suitable driver found for jdbc:h2

When I debug my Mule application i have error:
org.springframework.dao.DataAccessResourceFailureException: Error retrieving database metadata; nested exception is org.springframework.jdbc.support.MetaDataAccessException: Could not get Connection for extracting meta data; nested exception is org.springframework.jdbc.CannotGetJdbcConnectionException: Could not get JDBC Connection; nested exception is java.sql.SQLException: No suitable driver found for jdbc:h2:~/test
my java code:
SimpleJdbcCall call = new SimpleJdbcCall(jdbcTemplate.getDataSource()).withProcedureName("my_procedure_name").withSchemaName("my_schema");
...
call.execute(in)
my aaplicationContext:
<bean id="dataSource2"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="${db2.driver}" />
<property name="url" value="${db2.url}" />
<property name="username" value="${db2.user}" />
<property name="password" value="${db2.password}" />
</bean>
my app_name.properties:
db2.url=jdbc:h2:~/test
db2.driver=org.h2.Driver
db2.user=sa
db2.password=
my pom:
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<version>1.4.200</version>
</dependency>
my classpath:
<classpathentry kind="var" path="M2_REPO/com/h2database/h2/1.4.200/h2-1.4.200.jar"/>
log info after run application:
INFO org.springframework.jdbc.datasource.DriverManagerDataSource - Loaded JDBC driver: org.h2.Driver
Also i put h2-1.4.200.jar (when I starting my application from AnypointStudio) to:
c:\...\plugins\org.mule.tooling.server.3.9.0_6.4.0.201908221250\mule\lib\user\
and:
c:\...\plugins\org.mule.tooling.server.3.9.0_6.4.0.201908221250\mule\lib\boot\
and:
c:\...\plugins\org.mule.tooling.server.3.9.0_6.4.0.201908221250\mule\lib\mule\
and when I run application from mule server h2-1.4.200.jar, I put here:
..\mule-standalone-3.9.0\lib\boot
and
..\mule-standalone-3.9.0\lib\user
and:
..\mule-standalone-3.9.0\lib\mule
why application driver h2 not found ? what's the problem ?
Thanks.
You are mixing 3 different ways of managing the JDBC driver dependency, and also duplicating the library in the runtimes. That also makes it more difficult to understand the problem, and to deploy an application.
Let's start with Maven. It looks like you are using the right dependency in the pom, as long as it is in the section.
If the project is using Maven, there should not be any need to look into , unless it is out of sync with Maven. You should not change the class path manually, or edit the build path in Anypoint Studio. These are part of Studio/Eclipse .classpath files and should be left alone. Be sure to update the project so Studio regenerates the classpath.
About MULE_HOME\lib\boot, MULE_HOME\lib\user, MULE_HOME\lib\mule (either in Studio or standalone), you should not put the library in there. The Maven dependency is enough and you are duplicating the versions. Even if you can share a library in lib\user, it is not recommended. It makes more difficult to replicate sanely a deployment and again, there is no need for the JDBC driver. You should not put anything at all in lib\boot nor lib\mule nor the other subdirectories of lib. These are reserved for the runtime.
Try removing all those extras first and see what happens with a clean deployment.
Update:
Once the libraries are cleaned up, take into account that the Spring class may have some classloading issues itself. It is almost always better to use a datasource pool implementation. There are several to choose, like c3p0, dbcp, and others.
One example with c3p0:
<spring:bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">
<spring:property name="driverClass" value="${JDBC.driver}"/>
<spring:property name="jdbcUrl" value="${JDBC.URL}"/>
<spring:property name="user" value="${JDBC.user}"/>
<spring:property name="password" value="${JDBC.password}"/>
<spring:property name="minPoolSize" value="5"/>
<spring:property name="maxPoolSize" value="20"/>
</spring:bean>
See https://help.mulesoft.com/s/article/Spring-based-datasources for more examples.

StackoverflowExcepton in Spring message i18n ReloadableResourceBundleMessageSource

I am enabling message i18n in my Spring web app. For this, I have below code in my servlet.xml
<bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
<property name="basename" value="classpath:messages/message"/>
<property name="defaultEncoding" value="UTF-8"/>
</bean>
After adding above code, as soon as I hit my application in browser, I get below exception log:
SEVERE: Servlet.service() for servlet [default] in context with path [/ERP-Web] threw exception [Filter execution threw an exception] with root cause
java.lang.StackOverflowError
at org.springframework.context.support.ReloadableResourceBundleMessageSource.getMergedProperties(ReloadableResourceBundleMessageSource.java:235)
at org.springframework.context.support.ReloadableResourceBundleMessageSource.resolveCodeWithoutArguments(ReloadableResourceBundleMessageSource.java:176)
at org.springframework.context.support.AbstractMessageSource.getMessageInternal(AbstractMessageSource.java:209)
at org.springframework.context.support.AbstractMessageSource.getMessageFromParent(AbstractMessageSource.java:257)
where last 2 lines were repeated 100s of times and gives me StackoverflowException.
Exactly same exception is coming when I am using ResourceBundleMessageSource class.
My spring version is 4.3.6.RELEASE.
Below is content of my properties file
action.add.success = New {0} added successfully.
action.add.failure = Some error occurred in adding new {0}. Please try again later or contact administrator.
Sample project is on GitHub
I have tested your sample code in github and when running it has shown the error described, then modify the following:
Config:
<bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource">
<property name="basename" value="messages/message"/>
<property name="defaultEncoding" value="UTF-8"/>
</bean>
Class:
#RequestMapping(method=RequestMethod.GET)
#ResponseBody
public String getMessage() {
String msg = messageSource.getMessage("hello.world", null, LocaleContextHolder.getLocale());
return msg;
}
hello.word is the property with text in your file with name message_en.properties.
With this modifications the code run.
Edit for unknown message codes:
I tried with unknown message codes and the error was repeated, so I look at the registry and found that there could be more than one beans with the same name (potential circular references), but I have not detected why this happens, but if you It needs to work you have to rename the beans like this.
<bean id="myMessageSource" class="org.springframework.context.support.ResourceBundleMessageSource">
<property name="basename" value="messages/message"/>
<property name="defaultEncoding" value="UTF-8"/>
</bean>
and then use:
#Autowired
private MessageSource myMessageSource;
but i think this not resolve the principal problem with the circular potential error.
Very strange situation ;-)
The fundamental problem is that the messageSource gets auto-wired to itself (in the parentMessageSource property) because you use default-autowire="byType" this causes the stackoverflow exceptions for unknown message codes that messes up everything. Must say that logback adds mess to the mess as sometimes seems that the exception happens in its code, Log4J handles it better.
Autowiring is not good for big projects, and this your situation is a classical case of why, however if you must use it change the messageSource bean adding the following:
<property name="parentMessageSource"><null/></property>
In this way you wire yourself the parent and no autowiring happens.
This restores the normal situation in which not found messages are reported with a NoSuchMessageException
Then:
In controller you must request hello.world message, not message
You are missing a default resource, that is a no-locale-suffix file that represents the default locale or your application. In your case would be messages/message.properties To be simple the default locale of your application is that one for which you have all messages. Start with that and then add new languages (that might be incomplete).
Update
As far as I run your demo project:
Remove default-autowire="byType", which will set your message source's parent to itself, which causes stackoverflow;
Avoid LocaleContextHolder.getLocale(), which relay on system default locale;
Use right basename, which is different for ReloadableResourceBundleMessageSource and ResourceBundleMessageSource which solves following warning;
ResourceBundle [messages/message] not found for MessageSource: Can't find bundle for base name messages/message, locale en_US
Runnable example
StackTrace
As far as I could see from your stack trace, you may have three problems:
You don't supply arguments, but your property needs it;
The message source you have has cyclic dependency with its parent, which causes the StackOverflow (because AbstractMessageSource has a model like classloader, i.e. delegation to parent if it can't resolve);
I am not sure whether your properties is really found by message source, if it found, even with cyclic dependency, it will not StackOverflow;
Suggestions
When it comes to why there exists cyclic dependency, I can't tell whether it is a bug of spring or mis-configuration according to current info;
If you are not convenient to provide a example project, you may try 4.1.6 Relase, which I tried, works fine;
You may set log level to DEBUG or set breakpoint, to see whether you property file is really loaded;
The way you should use the ResourceBundleMessageSource is setting the path to the messages files on the basename property.
For example, if you have two messages files:
messages_en.properties
messages_es.properties
located at resources folder. Your bean configuration should be something like:
<bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource">
<property name="basename" value="messages" />
</bean>
Where messages is the prefix of the name of both files.
Maybe the Exception is thrown because Spring id trying to load the classpath automatically, and you have it included too, so it tries to load it again and again...
You can find a working example on Mkyong's.
This is what worked for me in my applicationContext.xml file:
<bean id="messageSource"
class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
<property name="basename" value="classpath:i18n/message" />
<property name="defaultEncoding" value="UTF-8" />
</bean>
<bean id="localeChangeInterceptor" class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor">
<property name="paramName" value="lang" />
</bean>
<bean id="localeResolver" class="org.springframework.web.servlet.i18n.CookieLocaleResolver">
<property name="defaultLocale" value="en"/>
</bean>
<bean id="handlerMapping"
class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping">
<property name="interceptors">
<ref bean="localeChangeInterceptor" />
</property>
</bean>
Note that i put the properties files in the follwoing path :
src/main/resources/i18n/message_en.properties

Using Locale from Resource Bundle in Java Spring

I'm learning to use resouce bundle for printing locale-dependent messages in my project.
application.xml:
<bean class="org.springframework.context.support.ResourceBundleMessageSource">
<property name="basename" value="ru.bpc.svat.svnr.integration.banking.messages" />
</bean>
<bean class="ru.bpc.svat.svnr.integration.banking.application.SpringContextMessageFactory" />
Directory src\main\resources\ru\bpc\svat\svnr\integration\banking contains files:
messages.properties
messages_ru.properties
messages_ru_RU.properties
each having line:
test = testmessage
In my test class I get an instance of message factory and try to get a message:
#Autowired private MessageFactory messageFactory;
...
messageFactory.getMessage("test", new Object[]{}, Locale.getDefault());
And then I get an exception:
No message found under code 'test' for locale 'ru_RU'.
What's wrong with it? This might be a foolish question, but it's my first experience. Thank you for your answers.
<bean id="messageSource"
class="org.springframework.context.support.ResourceBundleMessageSource">
<property name="basename">
<value>locale\customer\messages</value>
</property>
</bean>
</beans>
finally use SpringContext context.getMessage() method read your value.
Note: Assume your properties files are located at “resources\locale\customer\” folder.as mentioned in value tag above.
Basically those files needs to be in class-path of your project.
Let me know if it solves your problem, then accept my answer!
what if you place you files directly into src/main/resources (& not in subdirectory of src/main/resources? Just a thought.Normally, it should be able to find the file if it is there on classpath.
Try to replace:
<bean class="org.springframework.context.support.ResourceBundleMessageSource">
<property name="basename" value="ru.bpc.svat.svnr.integration.banking.messages" />
</bean>
on
<bean class="org.springframework.context.support.ResourceBundleMessageSource">
<property name="basename" value="ru\bpc\svat\svnr\integration\banking\messages" />
</bean>
make sure that the path relative from your class. In other case put resource in src/main/resources and use classpath:\ suffix

Spring - how to use PropertyPlaceholderConfigurer to dynamically load files

i have the next properties files with Spring Framework
config.properties
with content
environment=devel //posible values: devel, testing, prod
and with the previous environment property, choose some of the following files to load dynamically
config-service1-devel.properties
config-service1-testing.properties
config-service1-prod.properties
config-serviceN-devel.properties
config-serviceN-testing.properties
config-serviceN-prod.properties
and then, with spring i want load the properties, i'm solve to load the first properties file but i dont understand how to use expression language to complete the values of the dependent properties.
<bean id="MainApplicationProperties"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location"
value="file://#{systemProperties['jboss.server.home.dir']}/conf/services.properties" />
<property name="placeholderPrefix" value="$mainProperty{" />
<property name="placeholderSuffix" value="}" />
</bean>
<bean id="SecondApplicationProperties"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"
depends-on="MainApplicationProperties">
<property name="locations">
<list>
<value>file://#{systemProperties['jboss.server.home.dir']}/conf/serviceOne/service1-$mainProperty{environment}.properties</value>
<value>file://#{systemProperties['jboss.server.home.dir']}/conf/serviceTwo/service2-$mainProperty{environment}.properties</value>
<value>file://#{systemProperties['jboss.server.home.dir']}/conf/serviceN/serviceN-$mainProperty{environment}.properties</value>
</list>
</property>
</bean>
the error output is the next,
java.io.FileNotFoundException: /..../conf/serviceOne/service1-$mainProperty{environment}.properties (No such file or directory)
my opinion is, the value has not replaced
helpme, thanks
The problem is that when BeanFactoryPostProcessors are starting to be invoked, they are already instantiated. So even thou the first PropertyPlaceholderConfigurer modifies the bean definition of the second PropertyPlaceholderConfigurer, it has no effect as both beans have been already instantiated.

Categories

Resources