Use context parameters in junit test case - spring

In Spring,how to use context paramters in the tomcat location conf/context.xml in the junit testing or how to create context parameters in junit
<Context>
<Parameter name="mail_host" value="smtp.gmail.com" override="true"/>
</Context>
I am implementing the above parameters in my code as i specified below
#Value("#{contextParameters.mail_host}").It is working fine when i am using tomcat.
But i am getting an error 'Field or property 'contextParameters' cannot be found on object of type 'org.springframework.beans.factory.config.BeanExpressionContext'
when running in junit
Please help me,I am struggling in this point.Thanks in advance

You could construct JNDI before you run your test and in your test you can retrieve the information from context. Take a look a this example how he simulates injecting datasource using jndi here.
And your context would look something like this(in actual tomcat)
<Resource name="jdbc/TestDB"
auth="Container"
type="javax.sql.DataSource"
username="root"
password="password"
driverClassName="com.mysql.jdbc.Driver"
url="jdbc:mysql://localhost:3306/mysql"/>
So now we want to simulate this as if we would retrieve it using JNDI.
So in JUnit test cast we would like to setup Before class.Please note that not all information is shown here(constructing the datasource in #Before), but you got the point.
#BeforeClass
public static void setUpClass() throws Exception {
// rcarver - setup the jndi context and the datasource
try {
// Create initial context
System.setProperty(Context.INITIAL_CONTEXT_FACTORY,
"org.apache.naming.java.javaURLContextFactory");
System.setProperty(Context.URL_PKG_PREFIXES,
"org.apache.naming");
InitialContext ic = new InitialContext();
ic.createSubcontext("java:");
ic.createSubcontext("java:/comp");
ic.createSubcontext("java:/comp/env");
ic.createSubcontext("java:/comp/env/jdbc");
// Construct DataSource
OracleConnectionPoolDataSource ds = new OracleConnectionPoolDataSource();
ds.setURL("jdbc:oracle:thin:#host:port:db");
ds.setUser("MY_USER_NAME");
ds.setPassword("MY_USER_PASSWORD");
ic.bind("java:/comp/env/jdbc/nameofmyjdbcresource", ds);
} catch (NamingException ex) {
Logger.getLogger(MyDAOTest.class.getName()).log(Level.SEVERE, null, ex);
}
}
and in your test you can get this information
Context initContext = new InitialContext();
Context webContext = (Context)initContext.lookup("java:/comp/env");
DataSource ds = (DataSource) webContext.lookup("jdbc/nameofmyjdbcresource");
Hope it helps.
EDIT
e.g.
MyMailHost mailHost = new MyMailHost();
mailHost.setName("mail_host");
mailHost.setValue("smtp.gmail.com");
mailHost.setOverride(true);
ic.bind("java:/comp/env/jdbc/mymailhost", mailHost);
in #Test
Context initContext = new InitialContext();
Context webContext = (Context)initContext.lookup("java:/comp/env");
MyMailHost ds = (MyMailHost) webContext.lookup("jdbc/mymailhost");

One solution that I've used is to stub the context parameters in my test spring applicationContext file with a simple properties bean.
So in your case:
<util:properties id="contextParameters">
<prop key="mail_host">smtp.gmail.com</prop>
</util:properties>
This is the easiest way to handle it.
Hope it helps!

Related

Weblogic jndi NameNotFoundException occur with java config

I been searching again for this issue where I cannot locate the jndi database by using java config. Before this I use xml and its work perfectly but in java config it cause an issue;
Xml code:
<!-- Jndi database connection -->
<jee:jndi-lookup id="dbDataSource" jndi-name="${db.jndi}"
resource-ref="true" />
<beans:bean id="jdbcTemplate"
class="org.springframework.jdbc.core.JdbcTemplate" >
<beans:property name="dataSource" ref="dbDataSource"></beans:property>
</beans:bean>
Java config now:
#Bean(name = "dbDataSource")
public DataSource dataSource(#Value("${db.jndi}") String jndiName)
{
JndiDataSourceLookup lookup = new JndiDataSourceLookup();
return lookup.getDataSource(jndiName);
}
#Bean
public JdbcTemplate jdbcTemplate(DataSource ds) {
return new JdbcTemplate(ds);
}
Properties file:
db.jndi=jndi/myData
JNDI name in weblogic:
jndi/myData
After change to java config, sometimes the system can read the database but rarely occur, until I clean and restart my computer then it can find the database, but usually its always trigger:
javax.naming.NameNotFoundException: Unable to resolve 'jndi.myData'. Resolved 'jndi'; remaining name 'myData'
Why the application cannot find the database correctly?
Thanks!!!
I've had the same issue. If you're using 4.x version of spring that's probably the cause.
You should also check Weblogic's JNDI Tree. If your data source disapears from the tree after rebuilding the project, that's another symptom
If that's the case, what's happening is:
Your Datasource implements Closeable (and therefore AutoCloseable) and the context will always invoke the shutdown method regardless of your Bean definition
as seen here : SPR-12551: Document how to prevent a JNDI DataSource retrieved using JavaConfig to be removed on shutdown of the context
It's been marked as a documentation issue as this is the "expected" behaviour:
This issue was solely about documentation since we decided not to implement anything at the framework level
the solution, is to define the destroy method of the bean as empty, such as:
#Bean(name = "dbDataSource", destroyMethod="")
public DataSource dataSource(#Value("${db.jndi}") String jndiName)
{
JndiDataSourceLookup lookup = new JndiDataSourceLookup();
return lookup.getDataSource(jndiName);
}
#Bean
public JdbcTemplate jdbcTemplate(DataSource ds) {
return new JdbcTemplate(ds);
}
This is described in this issue (SPR-13022:Destroy callback cannot be disabled for AutoCloseable beans) .
PS: By the way, it seems like on early 4.x version of spring you couldn't override this behaviour by assingning destroyMethod. It apears that this bug was fixed on version 4.2 RC1.
I've had the same issue and I solved problem. I used to jndi datasource on weblogic. After I restart application, I notice my jndi datasource remove from Weblogic's JNDI Tree. Xml configuration works successfuly but java configuration don't work.
My old spring version: 4.1.6.RELEASE Upgrade to 4.3.9.RELEASE
Xml configuration like this;
<bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName">
<value>${db-jndi.name}</value>
</property>
</bean>
Java configuration like this;
#Bean(name = "dataSource")
public DataSource dataSource() throws IllegalArgumentException, NamingException
{
JndiTemplate jndiTemplate = new JndiTemplate();
DataSource dataSource = (DataSource) jndiTemplate.lookup(env.getProperty("db-jndi.name"));
logger.info("DataSource initialized in jndi ");
return dataSource;
}
Then i changed
#Bean(name = "dataSource")
to
#Bean(name = "dataSource", destroyMethod = "")
And it's works successfuly.
It looks like your datasource hasn't been deployed. You should look for JNDI tree for the server you tried to deploy datasource. (https://docs.oracle.com/cd/E12839_01/apirefs.1111/e13952/taskhelp/jndi/ViewObjectsInTheJNDITree.html) If you don't see "jndi.myData" on JNDI tree, you can assume that your datasource haven't been deployed. So you can go to your datasource monitoring tab and test the datasource. (https://docs.oracle.com/cd/E17904_01/apirefs.1111/e13952/taskhelp/jdbc/jdbc_datasources/TestDataSources.html)

persistence in hsqldb with spring

I'm struggling with persistence with spring and hsqldb. I checked out several questions but couldn't manage to find a solution:
Threads checked out:
No schema in file database after running program persisted to hsqldb:file via hibernate
HSQLDB and Hibernate/JPA - not persisting to disk?
Hibernate doesn't save any records in database
However this didn't help so far. Everytime I restart my webserver all changes are gone and nothing is written to my harddisk.
Hibernate configuration is as follows
#Bean
public AnnotationSessionFactoryBean sessionFactoryBean() {
Properties props = new Properties();
props.put("hibernate.dialect", HSQLDialect.class.getName());
props.put("hibernate.format_sql", "true");
props.put("hibernate.show_sql", "true");
props.put("hibernate.hbm2ddl.auto", "update");
props.put("hibernate.connection.url", "jdbc:hsqldb:file:c:\\temp\\rvec");
props.put("hibernate.connection.username", "sa");
props.put("hibernate.connection.password", "");
props.put("hibernate.connection.pool_size","1");
props.put("hibernate.connection.autocommit", "true");
AnnotationSessionFactoryBean bean = new AnnotationSessionFactoryBean();
bean.setAnnotatedClasses(new Class[]{Course.class, User.class, Event.class});
bean.setHibernateProperties(props);
bean.setDataSource(this.dataSource);
bean.setSchemaUpdate(true);
return bean;
}
data source and transaction manager are configured in servlet-context.xml
<tx:annotation-driven transaction-manager="transactionManager" />
There are no errors thrown in the console but only valid sql statements.
Any ideas?
Kind regards,
Lomu

Spring environment properties from file

I'm trying to figure out how to get the values of a properties file into my Spring Environment properties.
The pre Spring 3.1 way of doing this would be something like:
<context:property-placeholder location="classpath:my.properties" />
<bean id="myBean" class="com.whatever.MyBean">
<property name="someValue" value="${myProps.value}" />
<!-- etc -->
</bean>
I could have also done this:
public class MyBean {
#Value(value = "#{myProps.value}")
private String someValue;
}
Now that I can ostensibly pull properties from the Environment class, this seems like a much cleaner way of getting properties than using the clunky #{myProps.value} syntax in either my xml or my bean itself.
I tried this in my XML:
<bean
class="org.springframework.context.support.PropertySourcesPlaceholderConfigurer">
<property name="location">
<value>classpath:my.properties</value>
</property>
</bean>
But the properties are not added to Environment.
I understand that I can use the PropertySource attribute, but I'm not doing my configuration with annotations.
So how can I set up my bean / xml so that variables setup in my props are available in Environment? Moreover, how can I inject those values into my bean without having to explicitly say "environmentInstance.getProperty("myProps.value")?
For the web applications
If you want to have Environment populated before the XML bean definitions are processed, you should implement a ApplicationContextInitializer(), as described in the Spring Source blog
<context-param>
<param-name>contextInitializerClasses</param-name>
<param-value>com.bank.MyInitializer</param-value>
</context-param>
Here is a slightly modified version of the example from the blog
public class MyInitializer implements
ApplicationContextInitializer<ConfigurableWebApplicationContext> {
public void initialize(ConfigurableWebApplicationContext ctx) {
ResourcePropertySource ps;
try {
ps = new ResourcePropertySource(new ClassPathResource(
"my.properties"));
} catch (IOException e) {
throw new AssertionError("Resources for my.properties not found.");
}
ctx.getEnvironment().getPropertySources().addFirst(ps);
}
}
For the standalone applications
Basically the same thing, you can modify the environment of the AbstractApplicationContext directly
ResourcePropertySource ps;
try {
ps = new ResourcePropertySource(new ClassPathResource(
"my.properties"));
}catch (IOException e) {
throw new AssertionError("Resources for my.properties not found.");
}
//assuming that ctx is an AbstractApplicationContext
ctx.getEnvironment().getPropertySources().addFirst(ps);
P.S. the earlier version of this answer showed an attempt to modify the Environment from the bean but it seems to be an antipattern spreading on SO, because for sure you would like to have Environment property sources list populated even before the XmlBeanDefinitionReader starts to process XML to make placeholders work inside the <import/> statement.
My understanding is also a little addled but this is what I could make out:
Environment is a way to indicate the currently active profiles (and profiles are a way to selectively create beans)
PropertySources can be associated to an environment and the way to do that is using #PropertySource annotation, there does not seem to be an xml equivalent to do this.
Your understanding actually should be the other way round, AFAIK: when you declare <context:property-placeholder the placeholder will resolve properties against the locally declared properties and can fallback on the property sources declared in the environment, environment itself does not get modified with the new properties. Again,the only way to add properties to the environment itself seems to be through the #PropertySource annotation

Dynamic Dependency Injection Spring

I have following code inside my class
public void startListeners() throws Exception {
List<QueueConfiguration> queueConfigs = queueConfigResolver.getQueueConfigurations();
for(QueueConfiguration queueConfig : queueConfigs){
//TODO : work on this make it more testable
ICustomListener readerListener = new MyCustomListener(queueConfig);
readerListeners.add(readerListener);
readerListener.start();
}
}
I am using Spring for dependency injection(not in this case but overall). Now there two problems with this code.
I cannot put mock for each of the listeners created, while testing.
I dont want to use ApplicationContext.getBean() because it will have same affect. AFAIK spring cannot do this dynamically , but any other pointers?
As far as I can understand, you want to create a new bean instead of
ICustomListener readerListener = new MyCustomListener(queueConfig);
If that is the case, creating a factory for mycustomlistener and using
public abstract TestClient createTestClient();
to create your beans, and defining
<bean id="testClient" class="com.myproject.testbeans.TestClient" scope="prototype">
</bean>
<bean id="testClientFactory" class="com.myproject.testbeans.TestClientFactory">
<lookup-method name="createTestClient" bean="testClient" />
</bean>
in your context will solve your problem. This way, every time the createTestClient method of the factory is called, a new bean is created and given to your code. However, you have to give the config object via a setter instead of the constructor.

Getting a JDBC connection by JNDI in Spring JDBC

This page on Spring JDBC says
The DataSourceUtils class … provides static methods to obtain connections from JNDI
However the API doc for DataSourceUtils does not include the said static methods, as far as I can see.
What am I missing?
As I understand, what would be really useful to you is JndiObjectFactoryBean. This Spring factory bean returns object published in JNDI.
You would configure it like this, and then you would get the Connection using DataSourceUtils on the injected DataSource:
<bean name="myDataSourceInJndi" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName">
<value>java:comp/env/jdbc/MyDataSource</value>
</property>
</bean>
<bean name="myBean" class="MyClass">
...
<property name="dataSource" ref="myDataSourceInJndi">
...
</bean>
Hmm... Somehow, the Javadoc of DataSourceUtils is more "accurate" (I mean, the doc is not wrong but technically, you obtain a connection from a DataSource - that can be obtained via JNDI):
Helper class that provides static methods for obtaining JDBC Connections from a DataSource.
And the following methods should be what you're looking for:
DataSourceUtils.getConnection(DataSource)
DataSourceUtils.getGetConnection(DataSource)
Basic example (from the MySQL documentation):
// Create a new application context. this processes the Spring config
ApplicationContext ctx = new ClassPathXmlApplicationContext("ex1appContext.xml");
// Retrieve the data source from the application context
DataSource ds = (DataSource) ctx.getBean("dataSource");
// Open a database connection using Spring's DataSourceUtils
Connection c = DataSourceUtils.getConnection(ds);
try {
// retrieve a list of three random cities
PreparedStatement ps = c.prepareStatement(
"select City.Name as 'City', Country.Name as 'Country' " +
"from City inner join Country on City.CountryCode = Country.Code " +
"order by rand() limit 3");
ResultSet rs = ps.executeQuery();
while(rs.next()) {
String city = rs.getString("City");
String country = rs.getString("Country");
System.out.printf("The city %s is in %s%n", city, country);
}
} catch (SQLException ex) {
// something has failed and we print a stack trace to analyse the error
ex.printStackTrace();
// ignore failure closing connection
try { c.close(); } catch (SQLException e) { }
} finally {
// properly release our connection
DataSourceUtils.releaseConnection(c, ds);
}
For further future references: the jndi is managed on the application server i.e. : standalone.xml (Wildfly) with Postgresql driver:
<datasource jta="true" jndi-name="java:comp/env/jdbc/MyDataSource" pool-name="myDS" enabled="true">
<connection-url>jdbc:postgresql:[<//host>[:<5432>/]]<database></connection-url>
<driver>postgresql</driver>
<security>
<user-name>$USER</user-name>
<password>$PWD</password>
</security>
</datasource>

Resources