MessageSource and PropertyPlaceholderConfigurer cannot load messages but with classpath* - spring

My applicationContext.xml is in path:
src/main/resources/META-INF/spring
and property files are in path:
src/main/resources/messages
and I load spring context in web.xml as follows:
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:META-INF/spring/applicationContext.xml</param-value>
</context-param>
when I am configuring MessageSource and PropertyPlaceholderConfigurer as follows:
<bean id="propertyPlaceholderConfigurer"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<list>
<value>classpath:messages/apps.properties</value>
</list>
</property>
</bean>
<bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
<property name="basenames">
<list>
<value>classpath:messages/ValidationMessages</value>
<value>classpath:messages/app</value>
</list>
</property>
<property name="defaultEncoding" value="UTF-8"/>
</bean>
they both don't work, it only works when I change classpath to classpath*
Any ideas why?

From Spring documentation:
4.7.2.2 The classpath*: prefix
[...] location string may use the special classpath*: prefix: [...]
This special prefix specifies that all classpath resources that match the given name must be obtained [...], and then merged to form the final application context definition.
Are you sure there are no other messages/apps.properties files on your CLASSPATH coincidentally taking precedence and overriding your file? This description suggests that you might have several same named files that are merged when * is used.
Can you check this by calling:
SomeClass.class.getClassLoader().getResources("/messages/apps.properties");
?

Look at this excellent article for classpath v classpth* difference in regards to spring resource loading, I did some testing on your problem in my testing it worked whether i used classpath or classpath*
I am listing the code here about the test i did
I created a this directory structure (META-INF/spring under src/main/resource) placed context.xml
I am listing complete context.xml here
<?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-3.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<bean id="propertyPlaceholderConfigurer"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<list>
<value>classpath:messages/apps.properties</value>
</list>
</property>
</bean>
<bean class="prasanna.service.TestBean">
<property name="appName" value="${appname}"></property>
</bean>
<bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
<property name="basenames">
<list>
<value>classpath:messages/ValidationMessages</value>
<value>classpath:messages/apps</value>
</list>
</property>
<property name="defaultEncoding" value="UTF-8"/>
</bean>
</beans>
Listing for apps.properties
appname=spring mvc app
Listing for ValidationMessages.properties
error.name=Invalid name
TestBean is rather simple
public class TestBean
{
private String appName;
public String getAppName() {
return appName;
}
public void setAppName(String appName) {
this.appName = appName;
}
}
I am using a simple java class to load the property files and read them
public class LoadContext
{
public static void main(String[] args)
{
ApplicationContext ctx = new ClassPathXmlApplicationContext(new String[]{"classpath:META-INF/spring/context.xml"});
ReloadableResourceBundleMessageSource msgs = ctx.getBean(ReloadableResourceBundleMessageSource.class);
TestBean testBean = ctx.getBean(TestBean.class);
Assert.assertTrue(testBean.getAppName().equals("spring mvc app"));
String msg = msgs.getMessage("appname", new Object[]{new DefaultMessageSourceResolvable("appname")}, null);
System.out.println(" "+ msg);
String msg2 = msgs.getMessage("error.name", new Object[]{new DefaultMessageSourceResolvable("error.name")}, null);
System.out.println(" "+ msg2);
}
}

Related

Spring boot - 2 JNDI configuration

Posted my current configuration
#Configuration
public class Config {
#Value("${spring.datasource.primary.jndi-name}")
private String primaryJndiName;
#Value("${spring.datasource.secondary.jndi-name}")
private String secondaryJndiName;
#Primary
#Bean(destroyMethod = "") // destroy method is disabled for Weblogic update app ability
public DataSource primaryDs() {
JndiDataSourceLookup lookup = new JndiDataSourceLookup();
return lookup.getDataSource(primaryJndiName);
}
#Bean(destroyMethod = "") // destroy method is disabled for Weblogic update app ability
public DataSource secondaryDs() {
JndiDataSourceLookup lookup = new JndiDataSourceLookup();
return lookup.getDataSource(secondaryJndiName);
}
}
I implemented this way and it is working
you can put your jndi values in one properties file and then load that property file in your bean defination.xml
jndi.properties
#JNDI property for job repository
job.repository.db.connection=jdbc/pgDB
#JNDI property for application
application.db.connection=jdbc/db2Conn
Bean-defination.xml
<bean id="propertyPlaceholderConfigurer"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<list>
<value>classpath*:/properties/jndi.properties</value>
</list>
</property>
<property name="systemPropertiesModeName" value="SYSTEM_PROPERTIES_MODE_OVERRIDE" />
</bean>
<bean id="jobRepoDataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName" value="${job.repository.db.connection}" />
</bean>
<bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName" value="${application.db.connection}" />
</bean>

Spring Integration - JMS

I am trying to read a message from a JMS Queue (using ActiveMQ). Issue I am facing is, messages are being read from the queue, but not getting displayed in the "service-activator".
Any help is much appreciated.
My code is as below:
(1) Spring Configuration
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:int-jms="http://www.springframework.org/schema/integration/jms"
xmlns:jms="http://www.springframework.org/schema/jms"
xmlns:int="http://www.springframework.org/schema/integration"
xsi:schemaLocation="http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration.xsd
http://www.springframework.org/schema/jms http://www.springframework.org/schema/jms/spring-jms.xsd
http://www.springframework.org/schema/integration/jms http://www.springframework.org/schema/integration/jms/spring-integration-jms.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<!-- Component scan to find all Spring components -->
<context:component-scan base-package="com.poc.springinteg._3" />
<!-- -->
<bean id="remoteJndiTemplate" class="org.springframework.jndi.JndiTemplate" lazy-init="false">
<property name="environment">
<props>
<prop key="java.naming.provider.url">tcp://localhost:61616</prop>
<prop key="java.naming.factory.url.pkgs">org.apache.activemq.jndi</prop>
<prop key="java.naming.factory.initial">org.apache.activemq.jndi.ActiveMQInitialContextFactory</prop>
<prop key="connectionFactoryNames">DefaultActiveMQConnectionFactory,QueueConnectionFactory</prop>
<prop key="queue.SendReceiveQueue">org.apache.geronimo.configs/activemq-ra/JCAAdminObject/SendReceiveQueue</prop>
<prop key="queue.SendQueue">org.apache.geronimo.configs/activemq-ra/JCAAdminObject/MDBTransferBeanOutQueue</prop>
</props>
</property>
</bean>
<bean id="remoteConnectionFactory" class="org.springframework.jndi.JndiObjectFactoryBean" lazy-init="false">
<property name="jndiTemplate" ref="remoteJndiTemplate"/>
<property name="jndiName" value="QueueConnectionFactory"/>
<property name="lookupOnStartup" value="true" />
<property name="proxyInterface" value="javax.jms.ConnectionFactory" />
</bean>
<!-- Reading Queue -->
<bean id="inputQueue" class="org.apache.activemq.command.ActiveMQQueue">
<constructor-arg index="0">
<value>InputQueue_3</value>
</constructor-arg>
</bean>
<bean id="messageListenerContainer" class="org.springframework.jms.listener.DefaultMessageListenerContainer">
<property name="connectionFactory" ref="remoteConnectionFactory"/>
<property name="destination" ref="inputQueue"/>
<property name="sessionTransacted" value="true"/>
<property name="maxConcurrentConsumers" value="1"/>
<property name="concurrentConsumers" value="1"/>
<property name="autoStartup" value="true"/>
</bean>
<int:channel id="inbound"/>
<int-jms:message-driven-channel-adapter id="jmsIn"
channel="inbound"
container="messageListenerContainer" />
<int:service-activator input-channel="inbound"
ref="messageHandler"
method="onMessage"/>
<bean id="messageHandler" class="com.poc.springinteg._3.HelloServiceImpl"/>
</beans>
(2) Service Activator MDP:
package com.poc.springinteg._3;
import javax.jms.Message;
public class HelloServiceImpl
{
public String onMessage(Message name) {
System.out.println( "getHelloMessage:, " + name );
return "getHelloMessage:, " + name ;
}
}
(3) Application start class:
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class App {
public static void main( String[] args )
{
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:3_applicationContext.xml" );
applicationContext.registerShutdownHook();
}
}
Thanks
To make your onMessage(javax.jms.Message name) working you should specify extract-payload="false" on your <int-jms:message-driven-channel-adapter>:
/**
* Specify whether the JMS request Message's body should be extracted prior
* to converting into a Spring Integration Message. This value is set to
* <code>true</code> by default. To send the JMS Message itself as a
* Spring Integration Message payload, set this to <code>false</code>.
* #param extractRequestPayload true if the request payload should be extracted.
*/
public void setExtractRequestPayload(boolean extractRequestPayload) {
And quoting Reference Manual:
If extract-payload is set to true (which is the default), the received JMS Message will be passed through the MessageConverter. When relying on the default SimpleMessageConverter, this means that the resulting Spring Integration Message will have the JMS Message’s body as its payload. A JMS TextMessage will produce a String-based payload, a JMS BytesMessage will produce a byte array payload, and a JMS ObjectMessages Serializable instance will become the Spring Integration Message’s payload. If instead you prefer to have the raw JMS Message as the Spring Integration Message’s payload, then set 'extract-payload to false.
Got the solution to my problem:
Parameter type in method "onMessage" should be String:
import javax.jms.Message;
public class HelloServiceImpl
{
public String onMessage(String name) {
System.out.println( "getHelloMessage:, " + name );
return "getHelloMessage:, " + name ;
}
}

Injection of the sessionFactory not working

I'm new with Spring and I want to inject the sessionFactory and its not working at all. I'm starting a web server Jetty and then I load the context. After i start a GWT web application, I make a call on the server side and I try to get some info but I get a null pointer. There is no error at all so it make it difficult to know where the problem is. I know its suppose to work because I saw it working on a project I worked on some times ago. Any help will be appreciate. (Sorry for my possibly bad english)
Here is the context.xml :
<?xml version="1.0" encoding="UTF-8" ?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:security="http://www.springframework.org/schema/security"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema
/context/spring-context-3.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema
/tx/spring-tx-3.0.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema
/aop/spring-aop-3.0.xsd
http://www.springframework.org/schema/security http://www.springframework.org/schema
/security/spring-security-3.0.xsd">
<!-- Standard spring initialization -->
<context:component-scan base-package="com.test">
</context:component-scan>
<tx:annotation-driven transaction-manager="txManager"/>
<!-- Connection to the database-->
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-
method="close">
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://localhost:3306/test" />
<property name="username" value="root" />
<property name="password" value="123456789" />
</bean>
<!-- Hibernate session factory-->
<bean id="jpaSessionFactory"
class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="packagesToScan" value="com.domain"/>
<property name="namingStrategy" >
<bean class="org.hibernate.cfg.ImprovedNamingStrategy" />
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</prop>
<prop key="show_sql">true</prop>
<prop key="hibernate.hbm2ddl.auto">update</prop>
</props>
</property>
</bean>
<!-- Hibernate session factory -->
<bean id="txManager"
class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="jpaSessionFactory" />
</bean>
</beans>
Here is the main :
public static void main(String[] args) {
ContextHandlerCollection contexts = new ContextHandlerCollection();
contexts.setHandlers(new Handler[]
{ new AppContextBuilder().buildWebAppContext()});
final JettyServer jettyServer = new JettyServer();
jettyServer.setHandler(contexts);
Runnable runner = new Runnable() {
#Override
public void run() {
new ServerRunner(jettyServer);
}
};
EventQueue.invokeLater(runner);
new ClassPathXmlApplicationContext("context.xml");
}
Here is the class Test where I want the injection :
#Component("test")
public class TEST{
#Resource(name="jpaSessionFactory")
private SessionFactory sessionFactory;
#SuppressWarnings("unchecked")
#Transactional(readOnly = true)
public List<Personne> getPersonnes() {
Session s = sessionFactory.getCurrentSession();
Query query = s.createQuery("from Person");
return query.list();
}
}
Here is the server side from the application (not shown completely)
/*** The server side implementation of the RPC service.
*/
#SuppressWarnings("serial")
public class GreetingServiceImpl extends RemoteServiceServlet implements
GreetingService {
#Resource
private TEST t;
public String greetServer(String input) throws IllegalArgumentException {
// Verify that the input is valid.
if (!FieldVerifier.isValidName(input)) {
// If the input is not valid, throw an IllegalArgumentException
back to
// the client.
throw new IllegalArgumentException(
"Name must be at least 4 characters long");
}
t.getPersons(); // NULL pointer here
.........................
The MySQL tables are created like it should, so all the scanning seems to work.
Thanks
Bob
This is because the GreetingServiceImpl class is not created by spring - it is servlet that is initialized by the container directly. Follow the instructions in this article to fix the issue. I have copied the relevant code from the article.
#Override
public void init() throws ServletException {
super.init();
final WebApplicationContext ctx =
WebApplicationContextUtils.getWebApplicationContext(getServletContext());
if (ctx == null) {
throw new IllegalStateException("No Spring web application context found");
}
ctx.getAutowireCapableBeanFactory().autowireBeanProperties(this,
AutowireCapableBeanFactory.AUTOWIRE_BY_TYPE, true);
}

org.hibernate.HibernateException: No Session found for current thread

I'm getting the above exception with Spring3 and Hibernte4
The following is my bean xml file
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
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.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.1.xsd">
<context:annotation-config/>
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/GHS"/>
<property name="username" value="root"/>
<property name="password" value="newpwd"/>
</bean>
<bean id="sessionFactory"
class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="hibernateProperties">
<props>
<prop key="dialect">org.hibernate.dialect.MySQL5Dialect</prop>
</props>
</property>
<property name="packagesToScan">
<list>
<value>com.example.ghs.model.timetable</value>
</list>
</property>
</bean>
<bean id="baseDAO"
class="com.example.ghs.dao.BaseDAOImpl"/>
</beans>
My BaseDAO class looks like this
public class BaseDAOImpl implements BaseDAO{
private SessionFactory sessionFactory;
#Autowired
public BaseDAOImpl(SessionFactory sessionFactory){
this.sessionFactory = sessionFactory;
}
#Override
public Session getCurrentSession(){
return sessionFactory.getCurrentSession();
}
}
The following code throws the exception in the title
public class Main {
public static void main(String[] args){
ClassPathXmlApplicationContext context =
new ClassPathXmlApplicationContext("dao-beans.xml");
BaseDAO bd = (BaseDAO) context.getBean("baseDAO");
bd.getCurrentSession();
}
}
Does anyone have an idea about how to solve this problem?
getCurrentSession() only makes sense inside a scope of transaction.
You need to declare an appropriate transaction manager, demarcate boundaries of transaction and perform data access inside it. For example, as follows:
<bean id = "transactionManager" class = "org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name = "sessionFactory" ref = "sessionFactory" />
</bean>
.
PlatformTransactionManager ptm = context.getBean(PlatformTransactionManager.class);
TransactionTemplate tx = new TransactionTemplate(ptm);
tx.execute(new TransactionCallbackWithoutResult() {
public void doInTransactionWithoutResult(TransactionStatus status) {
// Perform data access here
}
});
See also:
10. Transaction Management
13.3 Hibernate
I came across same problem and got solved as below
Added #Transactional on daoImpl class
Added trnsaction manager in configuration file:
<tx:annotation-driven/>
<bean id="transactionManager"
class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory"></property>
</bean>
I'll just add something that took me some time to debug : don't forget that a #Transactional annotation will only work on "public" methods.
I put some #Transactional on "protected" ones and got this error.
Hope it helps :)
http://docs.spring.io/spring/docs/3.1.0.M2/spring-framework-reference/html/transaction.html
Method visibility and #Transactional
When using proxies, you should apply the #Transactional annotation
only to methods with public visibility. If you do annotate protected,
private or package-visible methods with the #Transactional annotation,
no error is raised, but the annotated method does not exhibit the
configured transactional settings. Consider the use of AspectJ (see
below) if you need to annotate non-public methods.
Which package u have put the BaseDAOImpl class in.. I think It requires a package name similar to the one u have used in the application context xml and it requires a relevant annotation too.

Spring - using static final fields (constants) for bean initialization

is it possible to define a bean with the use of static final fields of CoreProtocolPNames class like this:
<bean id="httpParamBean" class="org.apache.http.params.HttpProtocolParamBean">
<constructor-arg ref="httpParams"/>
<property name="httpElementCharset" value="CoreProtocolPNames.HTTP_ELEMENT_CHARSET" />
<property name="version" value="CoreProtocolPNames.PROTOCOL_VERSION">
</bean>
public interface CoreProtocolPNames {
public static final String PROTOCOL_VERSION = "http.protocol.version";
public static final String HTTP_ELEMENT_CHARSET = "http.protocol.element-charset";
}
If it is possible, what is the best way of doing this ?
Something like this (Spring 2.5)
<bean id="foo" class="Bar">
<property name="myValue">
<util:constant static-field="java.lang.Integer.MAX_VALUE"/>
</property>
</bean>
Where util namespace is from xmlns:util="http://www.springframework.org/schema/util"
But for Spring 3, it would be cleaner to use the #Value annotation and the expression language. Which looks like this:
public class Bar {
#Value("T(java.lang.Integer).MAX_VALUE")
private Integer myValue;
}
Or, as an alternative, using Spring EL directly in XML:
<bean id="foo1" class="Foo" p:someOrgValue="#{T(org.example.Bar).myValue}"/>
This has the additional advantage of working with namespace configuration:
<tx:annotation-driven order="#{T(org.example.Bar).myValue}"/>
don't forget to specify the schema location..
<?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:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.1.xsd">
</beans>
One more example to add for the instance above. This is how you can use a static constant in a bean using Spring.
<bean id="foo1" class="Foo">
<property name="someOrgValue">
<util:constant static-field="org.example.Bar.myValue"/>
</property>
</bean>
package org.example;
public class Bar {
public static String myValue = "SOME_CONSTANT";
}
package someorg.example;
public class Foo {
String someOrgValue;
foo(String value){
this.someOrgValue = value;
}
}
<util:constant id="MANAGER"
static-field="EmployeeDTO.MANAGER" />
<util:constant id="DIRECTOR"
static-field="EmployeeDTO.DIRECTOR" />
<!-- Use the static final bean constants here -->
<bean name="employeeTypeWrapper" class="ClassName">
<property name="manager" ref="MANAGER" />
<property name="director" ref="DIRECTOR" />
</bean>

Resources