Spring configuration: TypeMismatchException - spring

Using Spring 3.2 and Quartz 1.8. I've configured a org.springframework.scheduling.quartz.JobDetailBean as follows:
<bean id="a" class="org.springframework.scheduling.quartz.JobDetailBean">
<property name="jobClass" value="com.MyJob" />
...
</bean>
I'd like to change this configuration so that the jobClass refers to a bean instance so that I can set some properties on the bean:
<bean id="b" class"com.MyJob">
<constructor-arg name="arg" value="1"/>
</bean>
<bean id="a" class="org.springframework.scheduling.quartz.JobDetailBean">
<property name="jobClass" ref="b" />
...
</bean>
When launching the app with this config, I get
org.springframework.beans.TypeMismatchException: Failed to convert property value of type 'com.MyJob' to required type 'java.lang.Class' for property 'jobClass'.
Why is that? I assume it's because the jobClass property requires a class and not an instance, so how do I get around that?

Found a solution. You can inject some properties into the jobDataAsMap, which in turn injects them into setters into you jobClass (or can be retrieved programmatically from the JobExecutionContext.jobDetail in your jobClass).
<bean id="a" class="org.springframework.scheduling.quartz.JobDetailBean">
<property name="jobClass" value="com.MyJob" />
<property name="jobDataAsMap">
<map>
<entry key="propA" value="10" />
<entry key="propB" value="3" />
</map>
</property>
</bean>

Related

Spring factory-bean with property resolution

Is it possible to have property resolution on the factory-bean field of a Spring bean declaration?
Example:
<bean factory-bean="$APP{some.factory.bean}" factory-method="...">
Spring version: 3.2.4
Adding a PropertyPlaceholderConfigurer to your spring context should work:
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<list>
<value>classpath:yourfile.properties</value>
</list>
</property>
<property name="ignoreResourceNotFound" value="false" />
<property name="ignoreUnresolvablePlaceholders" value="false" />
</bean>
You can declare your propertyName in the file and then use it like:
<bean factory-bean="${propertyName}" factory-method="...">
Just encountered the same issue (using Spring 4.2.0). It seems that property resolution for factory beans does not work despite what they say in SPR-12638. I've ended up using ProxyFactoryBean as a workaround.
The desired configuration, which does not work:
<!-- The bean to be created: factory type determined in runtime -->
<bean id="..." factory-bean="factory-${factory.type}" factory-method="..." />
<!-- Possible factories -->
<bean id="factory-A" class="..." />
<bean id="factory-B" class="..." />
<bean id="factory-C" class="..." />
The workaround that I've found:
<!-- The bean to be created: use factory proxy -->
<bean id="..." factory-bean="factory-proxy" factory-method="..." />
<!-- The factory proxy: real factory type determined in runtime -->
<bean id="factory-proxy" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="target" ref="factory-${factory-type}" />
</bean>
<!-- Possible factories -->
<bean id="factory-A" class="..." />
<bean id="factory-B" class="..." />
<bean id="factory-C" class="..." />
Enjoy :)

XStream JavaBeanConverter Spring config to serialize using getter

I would like to register XStream JavaBeanConverter in Spring config. I see test examples where JavaBeanConverter is registered as below.
xstream.registerConverter(new JavaBeanConverter(xstream.getClassMapper(), "class"), -20);
But how do I set it up in my spring config.
Currently my spring config is setup as below
<bean
class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver">
<property name="order" value="1" />
<property name="mediaTypes">
<map>
<entry key="json" value="application/json" />
<entry key="xml" value="application/xml" />
</map>
</property>
<property name="defaultViews">
<list>
<bean class="org.springframework.web.servlet.view.json.MappingJacksonJsonView" >
<property name="renderedAttributes" value="document" />
</bean>
<bean class="org.springframework.web.servlet.view.xml.MarshallingView">
<property name="marshaller">
<bean class="org.springframework.oxm.xstream.XStreamMarshaller" p:autodetectAnnotations="true">
<property name="encoding" value="UTF-8" />
</bean>
</property>
<property name="contentType" value="application/xml;charset=UTF-8" />
<property name="modelKey" value="person" />
</bean>
</list>
</property>
<property name="ignoreAcceptHeader" value="true" />
</bean>
I am using xstream annotation for Alias and Converter.
I tried extending my custom converter from JavaBeanConverter. It serializes normal properties fine but I want it to serialize getXXX method.
public class MyCustomConverter extends JavaBeanConverter {
public MyCustomConverter(Mapper mapper) {
super(mapper);
}
#Override... marshal.. unmarshal... canConvert methods...
}
Thanks a lot!
Add this to your marshaller bean definition:
<property name="converters">
<util:list>
<bean class="com.MyBeanConverter">
<constructor-arg value="com.MyBean" index="0" />
</bean>
</util:list>
</property>
And then, define the following class that will implement the conversion
import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.converters.javabean.JavaBeanConverter;
public class MyBeanConverter extends JavaBeanConverter {
public MyBeanConverter(Class<?> theClass) {
super(new XStream().getMapper(), theClass);
}
}

Jackson+Spring3.0.5 custom object mapper

I am having a hard time configuring Jackson on my Spring application. I can get it to work, but it does not seem to accept any kind of configurations. Basically what i'm trying to achieve is have an ObjectMapper that scans for Spring format annotations.
What i am trying is this:
<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
<property name="messageConverters">
<list>
<bean
class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter">
<property name="objectMapper" ref="jacksonObjectMapper" />
</bean>
</list>
</property>
</bean>
<bean id="jacksonObjectMapper" class="ro.softwin.cnfp.ConversionServiceAwareObjectMapper" />
<bean
class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver">
<property name="mediaTypes">
<map>
<entry key="json" value="application/json" />
<entry key="html" value="text/html" />
</map>
</property>
<property name="viewResolvers">
<list>
<bean
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="viewClass"
value="org.springframework.web.servlet.view.JstlView" />
<property name="prefix" value="/jsp/" />
<property name="suffix" value=".jsp" />
</bean>
</list>
</property>
<property name="defaultViews">
<list>
<bean
class="org.springframework.web.servlet.view.json.MappingJacksonJsonView">
<property name="prefixJson" value="false" />
<property name="objectMapper" value="jacksonObjectMapper" />
</bean>
</list>
</property>
</bean>
The code for the mapper is :
public class ConversionServiceAwareObjectMapper extends ObjectMapper {
#Autowired
public ConversionServiceAwareObjectMapper(
ConversionService conversionService) {
AnnotationIntrospector introspector = AnnotationIntrospector.pair(
new FormatAnnotationIntrospector(conversionService),
DEFAULT_ANNOTATION_INTROSPECTOR);
this.setDeserializationConfig(this.getDeserializationConfig()
.withAnnotationIntrospector(introspector));
this.setSerializationConfig(this.getSerializationConfig()
.withAnnotationIntrospector(introspector).withSerializationInclusion(JsonSerialize.Inclusion.NON_NULL));
}
}
When initializing the server the following error occurs:
java.lang.IllegalStateException: Cannot convert value of type [java.lang.String] to required type [org.codehaus.jackson.map.ObjectMapper] for property 'objectMapper': no matching editors or conversion strategy found
at org.springframework.beans.TypeConverterDelegate.convertIfNecessary(TypeConverterDelegate.java:241)
at org.springframework.beans.BeanWrapperImpl.convertIfNecessary(BeanWrapperImpl.java:470)
... 55 more
I tried switching to a normal view resolver and just having the object mapper in the AnnotationMethodHandler, and that works regarding server start-up, but it just completely ignores any configuration.
I am completely at a loss as to what to do next.
Thanks for any help.
Update :
<property name="objectMapper" value="jacksonObjectMapper" />
with:
<property name="objectMapper" ref="jacksonObjectMapper" />
ref not value.

Spring resource

Problem: I want to make the below bean definitions (specified in aaplicationContext.xml) optional for "org.springframework.web.context.ContextLoaderListener". If i am not providing the "emsPropLocation" context parameter correctly, tomcat web container is not able to initialized properly and it is obvious reason. Is there any way to make it optional?
appicationContext.xml:
<bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="ignoreResourceNotFound" value="false"/>
<property name="location" value="file:/#{contextParameters.emsPropLocation}" />
</bean>
<!-- TIBCO Connection Factory Bean -->
<bean id="tibcoConnectionFactory" class="com.tibco.tibjms.TibjmsConnectionFactory">
<constructor-arg value="${emsServerURL}"/>
<property name="userName" value="${emsUserName}"/>
<property name="userPassword" value="${emsPassword}"/>
<property name="connAttemptCount" value="${connAttemptCount}"/>
<property name="connAttemptDelay" value="${connAttemptDelay}"/>
<property name="connAttemptTimeout" value="${connAttemptTimeout}"/>
<property name="reconnAttemptCount" value="${reconnAttemptCount}"/>
<property name="reconnAttemptDelay" value="${reconnAttemptDelay}"/>
<property name="reconnAttemptTimeout" value="${reconnAttemptTimeout}"/>
</bean>
<!-- bean id="tibcoUtil" class="com.nr.ns.upload.TibcoUtil" scope="singleton">
<constructor-arg value="true"/>
</bean-->
<bean id="jmsExceptionListener" class="com.nr.ns.upload.LogMsgExceptionListener"/>
<!-- Spring CachingConnectionFactory Bean -->
<bean id="connectionFactory" class="org.springframework.jms.connection.CachingConnectionFactory">
<constructor-arg ref="tibcoConnectionFactory"/>
<property name="reconnectOnException" value="${reconnectOnException}"/>
<property name="sessionCacheSize" value="${sessionCacheSize}"/>
<property name="exceptionListener" ref="jmsExceptionListener"/>
</bean>
<!-- JMSTemplate Bean -->
<bean id="jmsTemplate" class="org.springframework.jms.core.JmsTemplate">
<constructor-arg ref="connectionFactory"/>
<property name="receiveTimeout" value="${receiveTimeout}"/>
<property name="deliveryMode" value="${deliveryMode}"/>
</bean>
We are keeping WAR file outside tomcat and to make it happen we have "app.xml" file inside TOMCAT_HOME/conf/Catalina/localhost.
app.xml:
<Context path="/app"
docBase="/abc/ccp/app.war"
reloadable="true"
unpackWAR="false">
<Parameter name="emsPropLocation"
value="/xyz/config/EMSServerConf.properties"
override="false"/>
</Context>
have a try to change the ignoreResourceNotFound property of your propertyConfigurer to true.
If contextParameters.emsPropLocation is not set, this will default to what is afer the colon.
<property name="location" value="file:/#{contextParameters.emsPropLocation:/xyz/config/EMSServerConf.properties}" />

Calling spring bean from alfresco activiti process

Within alfresco activiti, could I call a spring bean using the servicetask like :
<serviceTask id="assignApplicationId" name="Assign Application Id"
activiti:expression="${sequenceUtil.getOutboundId(task.id)}"
activiti:resultVariable="OutboundWF_ApplicationNumber"/>
however, in my custom context I declared the sequenceUtil as the following:
<bean id="sequenceUtil" name="sequenceUtil" class="com.tts.mersal.presentation.bean.dialog.util.SequenceUtil">
<property name="searchService">
<ref bean="searchService" />
</property>
<property name="nodeService">
<ref bean="nodeService" />
</property>
<property name="workflowService">
<ref bean="WorkflowService" />
</property>
</bean>
Actually I got the following exception
org.activiti.engine.impl.javax.el.PropertyNotFoundException: Cannot resolve identifier 'sequenceUtil'
at org.activiti.engine.impl.juel.AstIdentifier.eval(AstIdentifier.java:83)
at org.activiti.engine.impl.juel.AstMethod.invoke(AstMethod.java:79)
at org.activiti.engine.impl.juel.AstMethod.eval(AstMethod.java:75)
at org.activiti.engine.impl.juel.AstEval.eval(AstEval.java:50)
at org.activiti.engine.impl.juel.AstNode.getValue(AstNode.java:26)
at org.activiti.engine.impl.juel.TreeValueExpression.getValue(TreeValueExpression.java:114)
at org.activiti.engine.impl.el.JuelExpression.getValue(JuelExpression.java:46)
I got it :)
I have to override the activitiProcessEngineConfiguration bean to include my custom bean within beans property
<!-- -->
<!-- Activiti Process Engine -->
<!-- -->
<bean id="activitiProcessEngineConfiguration"
class="org.alfresco.repo.workflow.activiti.AlfrescoProcessEngineConfiguration">
<property name="dataSource" ref="wrappedDataSource" />
<property name="transactionManager" ref="transactionManager" />
<property name="databaseSchemaUpdate" value="${db.schema.update}" />
<property name="history" value="full" />
<property name="jobExecutorActivate" value="true" />
<!-- Limit the visible beans in expressions -->
<property name="beans">
<map>
<entry key="services" value-ref="ServiceRegistry" />
<entry key="sequenceUtil" value-ref="sequenceUtil" />
</map>
</property>
<property name="customTypes">
<list>
<ref bean="activitiScriptNodeType" />
<ref bean="activitiScriptNodeListType" />
</list>
</property>
<property name="customPreBPMNParseListeners">
<list>
<ref bean="activitiParseListener" />
</list>
</property>
</bean>
There is a much better way to map bean names to el epressions. At least for alfresco 5.2.
Originally activitiProcessEngineConfiguration defined like that:
<bean id="activitiProcessEngineConfiguration" class="org.alfresco.repo.workflow.activiti.AlfrescoProcessEngineConfiguration">
<!-- Limit the visible beans in expressions -->
<property name="beans" ref="activitiBeanRegistry" />
</bean>
Where activitiBeanRegistry defined like that:
<util:map id="activitiBeanRegistry" map-class="java.util.HashMap">
<entry key="services" value-ref="ServiceRegistry" />
</util:map>
So you can easy add your beans with names without touching original activitiProcessEngineConfiguration. Like that:
<bean id="my.activitiBeanRegistry" class="org.springframework.beans.factory.config.MethodInvokingFactoryBean" depends-on="activitiBeanRegistry">
<property name="targetObject">
<ref bean="activitiBeanRegistry" />
</property>
<property name="targetMethod" value="put" />
<property name="arguments">
<list>
<value>sequenceUtil</value>
<ref bean="sequenceUtil" />
</list>
</property>
Open for extension closed for modification :)
Full source can be found here
See also activiti-context.xml

Resources