Bean property 'feedId' is not writable or has an invalid setter method. Does the parameter type of the setter match the return type of the getter? - spring

Below is code Batch snippet:
XML :
</beans:property> -->
<beans:bean id="RDFieldSetMapper" class="in.gov.tds.batch.mapper.RDFieldSetMapper"
autowire="byName" scope="step">
<!-- <beans:property name="feedId" value="429717"></beans:property> -->
<beans:property name="feedId" value="#{jobParameters[feedId]}"></beans:property>
</beans:bean>
setter method in Java Class:
recordDetail.setFeedId(new Long(feedId));
Please provide the resolution as I am getting Invalid setter method.
More Mapper detail:
public class RDFieldSetMapper implements FieldSetMapper {
private Long feedId;
private int batchCounter;
#Override
public RecordDetail mapFieldSet(FieldSet fieldSet) throws BindException {
if (LOGGER.isDebugEnabled())
LOGGER.debug("Record Detail Mapper:-- " + " " + fieldSet);
RecordDetail recordDetail = new RecordDetail();
// feedId = FeedReader.feedId;
recordDetail.setFeedId(new Long(feedId));
}
}

solved the problem. Issue : setter and getter methods are not present in the mapper class.
public Long getFeedId() {
return feedId;
}
public void setFeedId(Long feedId) {
this.feedId = feedId;
}

Related

javax.el.ELException: Cannot convert Protocol#7ebc9002 of type class Protocol to class Protocol$$EnhancerByCGLIB$$22af7fa3 (lazy loadding)

I struggle to make hibernate 3.1 lazy loading working with JSF 1.2
Caused by: javax.el.ELException: Cannot convert foo.bar.Protocol#7ebc9002 of type class foo.bar.Protocol to class foo.bar.Protocol$$EnhancerByCGLIB$$22af7fa3
at org.apache.el.lang.ELSupport.coerceToType(ELSupport.java:438)
at org.apache.el.ExpressionFactoryImpl.coerceToType(ExpressionFactoryImpl.java:46)
at com.sun.faces.renderkit.html_basic.RadioRenderer.renderOption(RadioRenderer.java:87)
at com.sun.faces.renderkit.html_basic.SelectManyCheckboxListRenderer.encodeEnd(SelectManyCheckboxListRenderer.java:146)
I read that hibernate will replace the lazy loading proxy on demand, but it seems to do not work on JSF converter call.
Note that Protocols are bound to radio buttons in the view
Do you know how to workaround this ? I can't find someone who have the same issue as me.
applicationContext :
<bean id="protocol" class="foo.bar.Protocol" abstract="false"
lazy-init="default" autowire="byName" dependency-check="default" scope="session">
<aop:scoped-proxy />
</bean>
<bean id="protocolConverter" class="foo.bar.ProtocolConverter" abstract="false"
lazy-init="default" autowire="byName" dependency-check="default" scope="singleton">
<property name="protocolDAO" ref="protocolDAO" />
</bean>
view :
<h:selectOneRadio value="#{pingControler.ping.protocol}" converter="#{protocolConverter}">
<f:selectItems value="#{pingControler.allProtocolsSelectItems}" />
<a4j:support event="onchange" reRender="foo1,foo2" />
</h:selectOneRadio>
ping :
public class Ping {
// Fields
private Integer pingId;
private Protocol protocol;
...
}
pingControler :
private Ping ping;
public void init(ActionEvent event) {
ping = new Ping();
}
public void save(ActionEvent event) throws Exception {
if (ping.getPingId() == null) {
pingPersistent.addPing(ping);
} else {
pingPersistent.updatePing(ping);
}
}
I figured out (finally) how to workaround this. I'm not sure if this is the proper way, but it works.
I added this code :
private static <T> T initializeAndUnproxy(T entity) {
if (entity == null) {
throw new NullPointerException("Entity passed for initialization is null");
}
Hibernate.initialize(entity);
if (entity instanceof HibernateProxy) {
entity = (T) ((HibernateProxy) entity).getHibernateLazyInitializer().getImplementation();
}
return entity;
}
And i called it in my Converter like this :
#Override
public Object getAsObject(FacesContext arg0, UIComponent arg1, String value) {
Protocol protocol = protocolDAO.findById(new Integer(value));
return initializeAndUnproxy(protocol);
}
instead of this :
#Override
public Object getAsObject(FacesContext arg0, UIComponent arg1, String value) {
return protocolDAO.findById(new Integer(value));
}
By the way, i did a mistake when i though that $$EnhancedByCGLIB$$ necessarily means an hibernate proxy. I read somewhere else that it's a library and could be used by Spring dependency injection too for example. Just to let you know.
I hope this will help the few jsf 1.2 / hibernate 3.1 users remaining. Should i upvote myself ?

MongoDB-Escape dots '.' in map key]

Map key codeofproduct contains dots but no replacement was configured! Make sure map keys don't contain dots in the first place or configure an appropriate replacement!
org.springframework.data.mapping.model.MappingException: Map key foo.bar.key contains dots but no replacement was configured! Make sure map keys don't contain dots in the first place or configure an appropriate replacement!
at org.springframework.data.mongodb.core.convert.MappingMongoConverter.potentiallyEscapeMapKey(MappingMongoConverter.java:622)
at org.springframework.data.mongodb.core.convert.MappingMongoConverter.writeMapInternal(MappingMongoConverter.java:586)
at org.springframework.data.mongodb.core.convert.MappingMongoConverter.createMap(MappingMongoConverter.java:517)
at org.springframework.data.mongodb.core.convert.MappingMongoConverter.writePropertyInternal(MappingMongoConverter.java:424)
at org.springframework.data.mongodb.core.convert.MappingMongoConverter$3.doWithPersistentProperty(MappingMongoConverter.java:386)
at org.springframework.data.mongodb.core.convert.MappingMongoConverter$3.doWithPersistentProperty(MappingMongoConverter.java:373)
at org.springframework.data.mapping.model.BasicPersistentEntity.doWithProperties(BasicPersistentEntity.java:257)
at org.springframework.data.mongodb.core.convert.MappingMongoConverter.writeInternal(MappingMongoConverter.java:373)
at org.springframework.data.mongodb.core.convert.MappingMongoConverter.writePropertyInternal(MappingMongoConverter.java:451)
at org.springframework.data.mongodb.core.convert.MappingMongoConverter$3.doWithPersistentProperty(MappingMongoConverter.java:386)
at org.springframework.data.mongodb.core.convert.MappingMongoConverter$3.doWithPersistentProperty(MappingMongoConverter.java:373)
at org.springframework.data.mapping.model.BasicPersistentEntity.doWithProperties(BasicPersistentEntity.java:257)
at org.springframework.data.mongodb.core.convert.MappingMongoConverter.writeInternal(MappingMongoConverter.java:373)
at org.springframework.data.mongodb.core.convert.MappingMongoConverter.writePropertyInternal(MappingMongoConverter.java:451)
at org.springframework.data.mongodb.core.convert.MappingMongoConverter$3.doWithPersistentProperty(MappingMongoConverter.java:386)
at org.springframework.data.mongodb.core.convert.MappingMongoConverter$3.doWithPersistentProperty(MappingMongoConverter.java:373)
at org.springframework.data.mapping.model.BasicPersistentEntity.doWithProperties(BasicPersistentEntity.java:257)
at org.springframework.data.mongodb.core.convert.MappingMongoConverter.writeInternal(MappingMongoConverter.java:373)
at org.springframework.data.mongodb.core.convert.MappingMongoConverter.writeInternal(MappingMongoConverter.java:345)
at org.springframework.data.mongodb.core.convert.MappingMongoConverter.write(MappingMongoConverter.java:310)
at org.springframework.data.mongodb.core.convert.MappingMongoConverter.write(MappingMongoConverter.java:77)
at org.springframework.data.mongodb.core.MongoTemplate.doSave(MongoTemplate.java:859)
at org.springframework.data.mongodb.core.MongoTemplate.save(MongoTemplate.java:806)
at org.springframework.data.mongodb.core.MongoTemplate.save(MongoTemplate.java:794)
When we try to insert value, this happens. How can we solve this?
this is my class
#Configuration
#EnableMongoRepositories("net.ooo.hepsiburada.**.repository")
#Profile(Constants.SPRING_PROFILE_CLOUD)
public class CloudMongoDbConfiguration extends AbstractMongoConfiguration {
private final Logger log = LoggerFactory.getLogger(CloudDatabaseConfiguration.class);
#Inject
private MongoDbFactory mongoDbFactory;
#Bean
public ValidatingMongoEventListener validatingMongoEventListener() {
return new ValidatingMongoEventListener(validator());
}
#Bean
public LocalValidatorFactoryBean validator() {
return new LocalValidatorFactoryBean();
}
#Bean
public CustomConversions customConversions() {
List<Converter<?, ?>> converterList = new ArrayList<>();;
converterList.add(DateToZonedDateTimeConverter.INSTANCE);
converterList.add(ZonedDateTimeToDateConverter.INSTANCE);
converterList.add(DateToLocalDateConverter.INSTANCE);
converterList.add(LocalDateToDateConverter.INSTANCE);
converterList.add(DateToLocalDateTimeConverter.INSTANCE);
converterList.add(LocalDateTimeToDateConverter.INSTANCE);
return new CustomConversions(converterList);
}
#Override
protected String getDatabaseName() {
return mongoDbFactory.getDb().getName();
}
#Override
public Mongo mongo() throws Exception {
return mongoDbFactory().getDb().getMongo();
}
}
When using Spring Data MongoDB you get an instance of: org.springframework.data.mongodb.core.convert.MappingMongoConverter that has mapKeyDotReplacement set to null by default - that is why you are getting an exception.
You need to either create your own instance of org.springframework.data.mongodb.core.convert.MappingMongoConverter or just modify existing instance using its provider setter method:
/**
* Configure the characters dots potentially contained in a {#link Map} shall be replaced with. By default we don't do
* any translation but rather reject a {#link Map} with keys containing dots causing the conversion for the entire
* object to fail. If further customization of the translation is needed, have a look at
* {#link #potentiallyEscapeMapKey(String)} as well as {#link #potentiallyUnescapeMapKey(String)}.
*
* #param mapKeyDotReplacement the mapKeyDotReplacement to set
*/
public void setMapKeyDotReplacement(String mapKeyDotReplacement) {
this.mapKeyDotReplacement = mapKeyDotReplacement;
}
In MongoDB, dot is always treated as a special character so avoiding it will most likely save you some other headache in the future.
EDIT:
To override default MappingMongoConverter add the following bean declaration:
#Bean
public MappingMongoConverter mongoConverter(MongoDbFactory mongoFactory) throws Exception {
DbRefResolver dbRefResolver = new DefaultDbRefResolver(mongoFactory);
MappingMongoConverter mongoConverter = new MappingMongoConverter(dbRefResolver, mongoMappingContext);
mongoConverter.setMapKeyDotReplacement(".");
return mongoConverter;
}
My exception:
org.springframework.data.mapping.MappingException: Map key VAT Registration No. contains dots but no replacement was configured! Make sure map keys don't contain dots in the first place or configure an appropriate replacement!
Field with a dot at the end: VAT Registration No.
This didn't work for me:
mongoConverter.setMapKeyDotReplacement(".");
mongoConverter.setMapKeyDotReplacement("_"); //this broke enum values for example VALUE_1 -> VALUE.1
This works for me:
mongoConverter.setMapKeyDotReplacement("-DOT")
Complete class:
#Configuration
public class MongoConfiguration {
#Bean
public MappingMongoConverter mongoConverter(MongoDbFactory mongoFactory, MongoMappingContext mongoMappingContext) {
DbRefResolver dbRefResolver = new DefaultDbRefResolver(mongoFactory);
MappingMongoConverter mongoConverter = new MappingMongoConverter(dbRefResolver, mongoMappingContext);
mongoConverter.setMapKeyDotReplacement("-DOT");
return mongoConverter;
}
}
For XML configuration following will be useful.
Note : mongoConverter bean is used for this. It will replace "." in key with "_"
<bean id="mappingContext" class="org.springframework.data.mongodb.core.mapping.MongoMappingContext" />
<mongo:auditing mapping-context-ref="mappingContext"/>
<mongo:db-factory id="mongoDbFactory" mongo-ref="mongoClient" dbname="${mongo.dbname}"/>
<bean id ="mongoConverter" class="org.springframework.data.mongodb.core.convert.MappingMongoConverter">
<constructor-arg name="mongoDbFactory" ref="mongoDbFactory"/>
<constructor-arg name="mappingContext" ref="mappingContext"/>
<property name="mapKeyDotReplacement" value="_"></property>
</bean>
<mongo:mongo-client id="mongoClient" credentials="${mongo.credential}" >
<mongo:client-options connections-per-host="50" threads-allowed-to-block-for-connection-multiplier="5000" />
</mongo:mongo-client>
<!-- MongoDB Template -->
<bean id="mongoTemplate" class="org.springframework.data.mongodb.core.MongoTemplate">
<constructor-arg name="mongoDbFactory" ref="mongoDbFactory"/>
<constructor-arg name="mongoConverter" ref="mongoConverter"/>
</bean>

Spring init-method params

I am new to spring and I wanted to ask whether or not it is possible to pass params to the init and destroy methods of a bean.
Thanks.
No, you can't. If you need parameters, you will have to inject them as fields beforehand.
Sample Bean
public class Foo{
#Autowired
private Bar bar;
public void init(){
bar.doSomething();
}
}
Sample XML:
<bean class="Foo" init-method="init" />
This method is especially useful when you cannot change the class you are trying to create like in the previous answer but you are rather working with an API and must use the provided bean as it is.
You could always create a class (MyObjectFactory) that implements FactoryBean and inside the getObject() method you should write :
#Autowired
private MyReferenceObject myRef;
public Object getObject()
{
MyObject myObj = new MyObject();
myObj.init(myRef);
return myObj;
}
And in the spring context.xml you would have a simple :
<bean id="myObject" class="MyObjectFactory"/>
protected void invokeCustomInitMethod(String beanName, Object bean, String initMethodName)
throws Throwable {
if (logger.isDebugEnabled()) {
logger.debug("Invoking custom init method '" + initMethodName +
"' on bean with beanName '" + beanName + "'");
}
try {
Method initMethod = BeanUtils.findMethod(bean.getClass(), initMethodName, null);
if (initMethod == null) {
throw new NoSuchMethodException("Couldn't find an init method named '" + initMethodName +
"' on bean with name '" + beanName + "'");
}
if (!Modifier.isPublic(initMethod.getModifiers())) {
initMethod.setAccessible(true);
}
initMethod.invoke(bean, (Object[]) null);
}
catch (InvocationTargetException ex) {
throw ex.getTargetException();
}
}
see spring soruce code in Method initMethod = BeanUtils.findMethod(bean.getClass(), initMethodName, null);
the init method is find and param is null
You cannot pass params to init-method but you can still achieve the same effect using this way:
<bean id="beanToInitialize" class="com.xyz.Test"/>
<bean class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
<property name="targetObject" ref="beanToInitialize" />
<property name="targetMethod" value="init"/> <!-- you can use any name -->
<property name="arguments" ref="parameter" /> <!-- reference to init parameter, can be value as well -->
</bean>
Note: you can also pass multiple arguments as a list using this
<property name="arguments">
<list>
<ref local="param1" />
<ref local="param2" />
</list>
</property>

Custom property editors do not work for request parameters in Spring MVC?

I'm trying to create a multiaction web controller using Spring annotations. This controller will be responsible for adding and removing user profiles and preparing reference data for the jsp page.
#Controller
public class ManageProfilesController {
#InitBinder
public void initBinder(WebDataBinder binder) {
binder.registerCustomEditor(UserAccount.class,"account", new UserAccountPropertyEditor(userManager));
binder.registerCustomEditor(Profile.class, "profile", new ProfilePropertyEditor(profileManager));
logger.info("Editors registered");
}
#RequestMapping("remove")
public void up( #RequestParam("account") UserAccount account,
#RequestParam("profile") Profile profile) {
...
}
#RequestMapping("")
public ModelAndView defaultView(#RequestParam("account") UserAccount account) {
logger.info("Default view handling");
ModelAndView mav = new ModelAndView();
logger.info(account.getLogin());
mav.addObject("account", account);
mav.addObject("profiles", profileManager.getProfiles());
mav.setViewName(view);
return mav;
}
...
}
Here is the part of my webContext.xml file:
<context:component-scan base-package="ru.mirea.rea.webapp.controllers" />
<context:annotation-config/>
<bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="mappings">
<value>
...
/home/users/manageProfiles=users.manageProfilesController
</value>
</property>
</bean>
<bean id="users.manageProfilesController" class="ru.mirea.rea.webapp.controllers.users.ManageProfilesController">
<property name="view" value="home\users\manageProfiles"/>
</bean>
<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter" />
However, when i open the mapped url, i get exception:
java.lang.IllegalArgumentException: Cannot convert value of type [java.lang.String] to required type [ru.mirea.rea.model.UserAccount]: no matching editors or conversion strategy found
I use spring 2.5.6 and plan to move to the Spring 3.0 in some not very distant future. However, according to this JIRA https://jira.springsource.org/browse/SPR-4182 it should be possible already in spring 2.5.1.
The debug shows that the InitBinder method is correctly called.
What am i doing wrong?
Update:
public class UserAccountPropertyEditor extends PropertyEditorSupport {
static Logger logger = Logger.getLogger(UserAccountPropertyEditor.class);
public UserAccountPropertyEditor(IUserDAO dbUserManager) {
this.dbUserManager = dbUserManager;
}
private IUserDAO dbUserManager;
public String getAsText() {
UserAccount obj = (UserAccount) getValue();
if (null==obj) {
return "";
} else {
return obj.getId().toString();
}
}
public void setAsText(final String value) {
try {
Long id = Long.parseLong(value);
UserAccount acct = dbUserManager.getUserAccountById(id);
if (null!=acct) {
super.setValue(acct);
} else {
logger.error("Binding error. Cannot find userAccount with id ["+value+"]");
throw new IllegalArgumentException("Binding error. Cannot find userAccount with id ["+value+"]");
}
} catch (NumberFormatException e) {
logger.error("Binding error. Invalid id: " + value);
throw new IllegalArgumentException("Binding error. Invalid id: " + value);
}
}
}
There are no errors logged from UserAccountPropertyEditor.
I don't think you want to be specifying the field argument to WebDataBinder.registerCustomEditor(). This intended to work alongside form-backing objects, and you're not using that.
Try the simpler 2-arg method instead, and it should work:
binder.registerCustomEditor(UserAccount.class, new UserAccountPropertyEditor(userManager));
binder.registerCustomEditor(Profile.class, new ProfilePropertyEditor(profileManager));

Spring AOP: applying properties through the aspect

The intent here is to deal with obfuscated passwords for resources.
We have an Advisor that intercepts calls to setPassword and decrypts the argument.
We've set up a template that looks somewhat like this:
<bean id="pwAdvisor" class="org.springframework.aop.support.NameMatchMethodPointcutAdvisor">
<property name="advice"><bean class="our.advice.bean.class"/></property>
<property name="mappedName" value="setPassword"/>
</bean>
<bean id="passwordHandlerTemplate" class="org.springframework.aop.framework.ProxyFactoryBean" abstract="true">
<property name="interceptorNames"><list><value>pwAdvisor</value></list></property>
</bean>
I'm unclear on the exact syntax to use it. The most obvious way is:
<bean id="myPasswordProtectedThing" parent="passwordHandlerTemplate">
<property name="target">
<bean class="the.target.class.name">
<property name="password" value="encrypted garbage"/>
</bean>
</property>
</bean>
But that doesn't work right, since the password property is applied to the inner bean, which means that the advisor won't wind up doing its work.
Well, what about this:
<bean id="myPasswordProtectedThing" parent="passwordHandlerTemplate">
<property name="target"><bean class="the.target.class.name"/></property>
<property name="password" value="encrypted garbage"/>
</bean>
Nope. Spring complains that the ProxyFactoryBean doesn't have a password property. And, of course, it doesn't. The thing that has the password property is the thing the factory bean creates.
Bueller?
My first effort was poor, but I was in hurry. I apologize. Now I think I know how it should work, because I believe I've implemented what you want myself.
I started with a Credential class (note: no interface):
package aop;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Credential
{
private static final String DEFAULT_USERNAME = "username";
private static final String DEFAULT_PASSWORD = "password";
private String username;
private String password;
public static void main(String[] args)
{
Credential cred1 = new Credential("foo", "bar");
System.out.println("created using new: " + cred1);
ApplicationContext context = new ClassPathXmlApplicationContext("classpath:aop-context.xml");
Credential cred2 = (Credential) context.getBean("credential");
System.out.println("created using app context: " + cred2);
String password = ((args.length > 0) ? args[0] : "baz");
cred2.setPassword(password);
System.out.println("initialized using setter: " + cred2);
}
public Credential()
{
this(DEFAULT_USERNAME, DEFAULT_PASSWORD);
}
public Credential(String username, String password)
{
this.setUsername(username);
this.setPassword(password);
}
public String getUsername()
{
return username;
}
public void setUsername(String username)
{
this.username = username;
}
public String getPassword()
{
return password;
}
public void setPassword(String password)
{
this.password = password;
}
public String toString()
{
return new StringBuilder().append("Credential{").append("username='").append(username).append('\'').append(", password='").append(password).append('\'').append('}').toString();
}
}
I created a Decryptor interface:
package aop;
public interface Decryptor
{
String decrypt(String encrypted);
}
And a DecryptorImpl:
package aop;
public class DecryptorImpl implements Decryptor
{
public static final String DEFAULT_DECRYPTED_VALUE = " - not secret anymore";
public String decrypt(String encrypted)
{
// Any transform will do; this suffices to demonstrate
return encrypted + DEFAULT_DECRYPTED_VALUE;
}
}
I needed DecryptorAdvice to implement Spring's MethodBeforeAdvice:
package aop;
import org.springframework.aop.MethodBeforeAdvice;
import java.lang.reflect.Method;
public class DecryptionAdvice implements MethodBeforeAdvice
{
private Decryptor decryptor;
public DecryptionAdvice(Decryptor decryptor)
{
this.decryptor = decryptor;
}
public void before(Method method, Object[] args, Object target) throws Throwable
{
String encryptedPassword = (String) args[0];
args[0] = this.decryptor.decrypt(encryptedPassword);
}
}
And I wired it together in an aop-context.xml. (If you tell me how to get XML to display, I'll post it.) Note the passwordDecryptionAdvisor: it only matches the setPassword method.
The interesting part happens when I run it. Here's what I see in the console:
created using new: Credential{username='foo', password='bar'}
created using app context: Credential{username='stackoverflow', password='encrypted-password'}
initialized using setter: Credential{username='stackoverflow', password='baz - not secret anymore'}
What this tells me is:
If I create an object with new it's
not under Spring's control, advice
isn't applied.
If I call setPassword in the ctor
before the app context is
initialized, advice isn't applied.
If I call setPassword in my code
after the app context is
initialized, advice is applied.
I hope this can help you.
I thought you wanted the beforeMethod advice to use the encrypted password String that's passed into the setPassword method. You want to decrypt that and have the advised class get an decrypted version.
I also don't see a proxy interface set in your proxy factory. "Spring In Action" says "...Creating a proxy with interfaces is favored over proxying classes..." Proxying classes should be the exception, not the rule.
Post your advice class.

Resources