Spring batch/integration bean initialization error for remote directory in outbound adapter - spring

I am trying to use spring batch/integration in the following way:
<bean id="ftpRemoteDirectory" class="java.lang.String" scope="step">
<constructor-arg type="java.lang.String" value="#{jobExecutionContext.get ('batchProperties').getProperty('remote.directory')}"/>
</bean>
<int-sftp:outbound-channel-adapter id="sftpOutboundAdapter"
channel="sftpChannel"
session-factory="sftpSessionFactory"
remote-directory-expression="#{ ftpRemoteDirectory }"
charset="UTF-8"
use-temporary-file-name="false"/>
However I receive the following error:
Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name '(inner bean)#13': Unsatisfied dependency expressed through constructor argument with index 0 of type [java.lang.String]: Could not convert constructor argument value of type [com.sun.proxy.$Proxy12] to required type [java.lang.String]: Failed to convert value of type 'com.sun.proxy.$Proxy12 implementing java.io.Serializable,java.lang.Comparable,java.lang.CharSequence,org.springframework.aop.scope.ScopedObject,org.springframework.aop.framework.AopInfrastructureBean,org.springframework.aop.SpringProxy,org.springframework.aop.framework.Advised' to required type 'java.lang.String'; nested exception is java.lang.IllegalStateException: Cannot convert value of type [com.sun.proxy.$Proxy12 implementing java.io.Serializable,java.lang.Comparable,java.lang.CharSequence,org.springframework.aop.scope.ScopedObject,org.springframework.aop.framework.AopInfrastructureBean,org.springframework.aop.SpringProxy,org.springframework.aop.framework.Advised] to required type [java.lang.String]: no matching editors or conversion strategy found
The goal is to have remote-directory populated from the arguments passed into the JVM from spring batch admin. That is why scope="step" is present on the ftpRemoteDirectory bean - so that we have access to the jobExecutionContext object. So, i'm trying to get the property from the jobExecutionContext and then inject it into the remote-directory attribute of the outbound channel adapter.
I'd be open to suggestions for other ways to do this as well - I just can't get it to work. Thanks!

Related

Spring EL template in a spring bean definition

I have a bean that has a map injected. The entries in the map are of type myBean (see below) and are defined in my spring XML. It may be that not all properties of myBean are defined in the xml, so I thought I would provide defaults in the form of a template where the variable bit in the template is provided by another property that will be present (p1 below). I hope that makes sense.
I am sure there are other ways to achieve this; well, I know there are, but I am new to Spring and I came across Spring EL and it sounded like it was suited to this kind of thing, so I tried this:
<bean id="myDefaults" class="com.myco.MyDefaults">
<property name="prop1" value="abc#{this.p1}def"/>
</bean>
<bean id="myBean" class="com.myco.MyBean" abstract="true">
<property name="theDefaults" ref="myDefaults"/>
</bean>
In MyBean the value of p1 is 100, and I was hoping that the value of theDefaults would be abc100def, but instead I get an error:
Error creating bean with name 'myDefaults' defined in class path resource [myapp-spring.xml]:
Initialization of bean failed; nested exception is
org.springframework.beans.factory.BeanExpressionException: Expression parsing failed; nested exception is
org.springframework.expression.spel.SpelEvaluationException: EL1008E:(pos 0): Field or property 'this' cannot be found on object of type 'org.springframework.beans.factory.config.BeanExpressionContext'
Thanks for any help
Paul
The variable is #this, not this but in any case, it's not needed in this context, it's implied.
Use value="abc#{p1}def"

Is it possible to populate spring util:list via properties file?

I would like to populate transport End points via properties file. I tried this but it didn't work
<util:properties id="cxfProperties" location="/WEB-INF/classes/cxf.properties" />
<util:list id="transportEndpoints">
<!--
<value>http://localhost:8080/doubleit/services/doubleit.*</value>
-->
<value>#{cxfProperties.service.wsdllocation}</value>
</util:list>
In my properties file I have
service.wsdllocation=http://localhost:8080/doubleit/services/doubleit.*
I get error:
Expression parsing failed; nested exception is
org.springframework.expression.spel.SpelEvaluationException:
EL1008E:(pos 14): Field or property 'service' cannot be found on
object of type 'java.util.Properties'
I don't think SpEL provides direct field access syntax for property in Properties. So I think the correct syntax should be:
#{cxfProperties.getProperty('service.wsdllocation')}
or
#{cxfProperties.getProperty('service.wsdllocation', 'SOME_DEFAULT_VAL')}

Spring AOP IllegalArgumentException: Cannot convert value of type [$Proxy12

I am trying to configure one advice in an existing spring project.
Following configuration works fine for a single package but when pointcut expression try to apply that advice on all packages its giving following error.
My Configuration:
<aop:config>
<aop:pointcut id="loggingPointcut" expression="execution(* com.abc.businessprocess.operation..*.execute(..))" />
<aop:advisor id="methodLoggingAdvisor" advice-ref="methodLoggingAdvice" pointcut-ref="loggingPointcut" />
</aop:config>
I tried with annotation also but it was giving same error.
I tried with CGLIB also even after using that its giving same error.
Error:
Caused by: org.springframework.beans.TypeMismatchException: Failed to convert property value of type [$Proxy12 implementing com.fmr.ast.common.businessprocess.util.Timeable,com.fmr.ast.common.businessprocess.operation.Operation,com.fmr.commons.taskmanager.core.Task,org.springframework.aop.SpringProxy,org.springframework.aop.framework.Advised] to required type [com.fmr.ips.businessprocess.operation.goalsetup.GetLeveledIRGExpInc] for property 'getRawDetailedLeveledExpInc'; nested exception is java.lang.IllegalArgumentException: Cannot convert value of type [$Proxy12 implementing com.fmr.ast.common.businessprocess.util.Timeable,com.fmr.ast.common.businessprocess.operation.Operation,com.fmr.commons.taskmanager.core.Task,org.springframework.aop.SpringProxy,org.springframework.aop.framework.Advised] to required type [com.fmr.ips.businessprocess.operation.goalsetup.GetLeveledIRGExpInc] for property 'getRawDetailedLeveledExpInc': no matching editors or conversion strategy found
at org.springframework.beans.BeanWrapperImpl.convertForProperty(BeanWrapperImpl.java:391)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.convertForProperty(AbstractAutowireCapableBeanFactory.java:1289)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyPropertyValues(AbstractAutowireCapableBeanFactory.java:1250)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1010)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:472)
... 33 more
Caused by: java.lang.IllegalArgumentException: Cannot convert value of type [$Proxy12 implementing com.fmr.ast.common.businessprocess.util.Timeable,com.fmr.ast.common.businessprocess.operation.Operation,com.fmr.commons.taskmanager.core.Task,org.springframework.aop.SpringProxy,org.springframework.aop.framework.Advised] to required type [com.fmr.ips.businessprocess.operation.goalsetup.GetLeveledIRGExpInc] for property 'getRawDetailedLeveledExpInc': no matching editors or conversion strategy found
at org.springframework.beans.TypeConverterDelegate.convertIfNecessary(TypeConverterDelegate.java:231)
at org.springframework.beans.TypeConverterDelegate.convertIfNecessary(TypeConverterDelegate.java:138)
at org.springframework.beans.BeanWrapperImpl.convertForProperty(BeanWrapperImpl.java:386)
... 37 more
Looking at the exception trace this is what I suspect:
GetLeveledIRGExpInc is a concrete class that implements three interfaces: Timeable, Operation, Task. You have a bean of this type declared in your context, which gets proxied because of your AOP config. This means that the runtime type of the bean won't be GetLeveledIRGExpInc any more, it will be $Proxy12 (JDK proxy) which still implements the above three interfaces, but is not a subtype of the concrete class GetLeveledIRGExpInc.
There is another bean somewhere in your context that needs a bean of this type to be injected into a property named getRawDetailedLeveledExpInc. When Spring tries to inject the proxied bean into that property, it fails, because the property's type is incompatible with the bean's runtime type.
The fundamental problem is that you try to apply a very generic logging aspect using JDK proxying mechanism which can only advise methods declared on interfaces. Try using <aop:config proxy-target-class="true"> so that classes without implemented interfaces can be advised as well. This would resolve the above detailed problem, as the generated CGLIB proxy for GetLeveledIRGExpInc will actually be a subtype of it. (Don't forget to add cglib to your dependencies for this to work.)

How to assign java.util.logging.Level to a bean?

I created an application and want to config its logging.Level thorugh bean
<bean id="loggingLevel" class="java.util.logging.Level"> <constructor-arg> <value>INFO</value> </constructor-arg> </bean>
but it failed. Here is the error message:
Unsatisfied dependency expressed through constructor argument with index 1 of type [int]: Ambiguous constructor argument types - did you specify the correct bean references as constructor arguments?
So how to do it the right way?
Instances of java.util.logging.Level are not intended to be instantiated this way, they should be obtained from static fields. In Spring you may use <util:constant>:
<util:contstant id = "loggingLevel" static-field="java.util.logging.Level.INFO" />

Problems overriding a property to null in Spring bean declaration

Just wondering if there is a way in Spring to have a parent controller:
<bean id="parentController" class="org.springframework.web.portlet.mvc.SimpleFormController" abstract="true">
<property name="validator" ref="validatorImpl"/>
...
</bean>
, and a class extending it:
<bean id="child1Controller" class="com.portlet.controller.Child1Controller" parent="parentController">
<property name="validator"><null/></property>
...
</bean>
<bean id="child2Controller" class="com.portlet.controller.Child2Controller" parent="parentController">
...
</bean>
, in such a way that the child overrides a property to null.
I know if you don't declare the property in either the parent or the child, you get the wanted effect, but as in most of the places validator refers to validatorImpl, I thought as a inheritance principle, I would be able to override a property to null.
I keep getting:
15:29:50,141 ERROR [PortletHotDeployListener:534] org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'childController' defined in PortletContext resource [/WEB-INF/context/sugerencia-context.xml]: Initialization of bean failed; nested exception is java.lang.NullPointerException
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'childController' defined in PortletContext resource [/WEB-INF/context/sugerencia-context.xml]: Initialization of bean failed; nested exception is java.lang.NullPointerException
On the other hand,
<bean id="parentController" class="org.springframework.web.portlet.mvc.SimpleFormController" abstract="true">
...
</bean>
<bean id="child1Controller" class="com.portlet.controller.Child1Controller" parent="parentController">
...
</bean>
<bean id="child2Controller" class="com.portlet.controller.Child2Controller" parent="parentController">
<property name="validator" ref="validatorImpl"/>
...
</bean>
Thanks.
Explicitly setting a property to <null/> isn't the same as not setting it. The property's setter method may check that the value you're injecting is non-null, for example.
If you look at the source code for BaseCommandController (which is a superclass of your controller), you'll see that setValidator does no such checking. However, when the bean is initialized in initApplicationContext(), it iterates over the array of validators, assuming they're all non-null, and will throw a NPE if there's a null in that array, which if likely what's happening here.
Unfortunately, there is no way to "unset" a property that has been configured in a parent bean definition. You'll need to rearrange the definitions so that the parent doesn't set it.
I think the problem is in your parent you are either using the validator in either setter method or in afterPropertiesSet. That may be the reason for the NPE. Check it once, if you are not using the validator which in your case is null anywhere in the initialization phases in your parent class, it should work fine.

Resources