You are viewing a plain text version of this content. The canonical link for it is here.
Posted to user@struts.apache.org by "durbinjo593@gmail.com" <du...@gmail.com> on 2008/07/29 07:45:15 UTC

custom converter takes String representation of long ID and replaces with Object - convertFromString not being called

I'm running into an issue where a converter i've setup is failing (or
appears) to fail to execute. First, might I make the assumption that type
converters and validators can be represented as beans. Reason being is
because I need to be able to do dependency injection via spring.

So, my problem is this: I've got an object 'CostCode' that has several
primitive properties and one 'Organization' object property. When the user
submits the form below, the validation specifications fail because the
system expects an Organization object as costCode.organization and instead
the validation processes receive a String representation of a LongID (the
long ID of the chosen Organization).

So, I thought, this is a perfect opportunity to use a converter... It's not
working, though. See the code below:

### RELEVANT TEMPLATE CODE ###
<s:form ... >
<s:textfield name="costCode.code" maxlength="20"></s:textfield>
...
<s:select name="costCode.organization" list="organizations" listKey="id"
listValue="name" label="Organization..." />
</s:form>

### xwork-conversion.properties ###
com.ktm.tt.model.organization.Organization=com.ktm.tt.struts.converters.organization.OrganizationConverter

### com.ktm.tt.struts.converters.organization.OrganizationConverter ###
package com.ktm.tt.struts.converters.organization;

import java.util.Map;

import org.apache.log4j.Logger;
import org.apache.struts2.util.StrutsTypeConverter;

import com.ktm.tt.dao.hibernate.organization.impl.OrganizationDaoImpl;

public class OrganizationConverter extends StrutsTypeConverter {

private OrganizationDaoImpl organizationDao;
private static final Logger LOG =
Logger.getLogger(OrganizationConverter.class);

public Object convertFromString(Map context, String[] values, Class toClass)
{
Long organizationID = new Long(values[4]);
LOG.debug("running OrganizationConverter.convertFromString!!!");
return organizationDao.findById(organizationID);
}

public String convertToString(Map context, Object o) {
LOG.debug("running OrganizationConverter.convertToString!!!");
return null;
}

public OrganizationDaoImpl getOrganizationDao() {
return organizationDao;
}

public void setOrganizationDao(OrganizationDaoImpl organizationDao) {
this.organizationDao = organizationDao;
}
}

### RELEVANT LOG OUTPUT
96 [KTMTT] DEBUG [2008/07/28 22:50:41] | processing conversion file
[xwork-conversion.properties]
97 [KTMTT] DEBUG [2008/07/28 22:50:41] |
com.ktm.tt.model.organization.Organization:com.ktm.tt.struts.converters.organization.OrganizationConverter
[treated as TypeConverter
com.ktm.tt.struts.converters.organization.OrganizationConverter@2424c672]
...
514 [KTMTT] DEBUG [2008/07/28 22:51:22] | Setting params costCode.type => [
three ] costCode.code => [ oneone ] costCode.unit => [ four ] costCode.label
=> [ twotwo ] costCode.organization => [ 10 ]
515 [KTMTT] DEBUG [2008/07/28 22:51:22] | Entering nullPropertyValue
[target=[com.ktm.tt.struts.action.organization.CreateCostCode@5e857066,
com.opensymphony.xwork2.DefaultTextProvider@7fefa490], property=costCode]
516 [KTMTT] DEBUG [2008/07/28 22:51:22] | Property: code
517 [KTMTT] DEBUG [2008/07/28 22:51:22] | Class:
com.ktm.tt.model.organization.CostCode
518 [KTMTT] DEBUG [2008/07/28 22:51:22] | converter is null for property
code. Mapping size: 0
519 [KTMTT] DEBUG [2008/07/28 22:51:22] | field-level type converter for
property [code] = none found
520 [KTMTT] DEBUG [2008/07/28 22:51:22] | Property: costCode.code
521 [KTMTT] DEBUG [2008/07/28 22:51:22] | Class:
com.ktm.tt.struts.action.organization.CreateCostCode
522 [KTMTT] DEBUG [2008/07/28 22:51:22] | converter is null for property
costCode.code. Mapping size: 0
523 [KTMTT] DEBUG [2008/07/28 22:51:22] | global-level type converter for
property [code] = none found
524 [KTMTT] DEBUG [2008/07/28 22:51:22] | falling back to default type
converter [com.opensymphony.xwork2.util.XWorkBasicConverter@26f6852d]
525 [KTMTT] DEBUG [2008/07/28 22:51:22] | Property: label
526 [KTMTT] DEBUG [2008/07/28 22:51:22] | Class:
com.ktm.tt.model.organization.CostCode
527 [KTMTT] DEBUG [2008/07/28 22:51:22] | field-level type converter for
property [label] = none found
528 [KTMTT] DEBUG [2008/07/28 22:51:22] | Property: costCode.label
529 [KTMTT] DEBUG [2008/07/28 22:51:22] | Class:
com.ktm.tt.struts.action.organization.CreateCostCode
530 [KTMTT] DEBUG [2008/07/28 22:51:22] | global-level type converter for
property [label] = none found
531 [KTMTT] DEBUG [2008/07/28 22:51:22] | falling back to default type
converter [com.opensymphony.xwork2.util.XWorkBasicConverter@26f6852d]
532 [KTMTT] DEBUG [2008/07/28 22:51:22] | Property: organization
533 [KTMTT] DEBUG [2008/07/28 22:51:22] | Class:
com.ktm.tt.model.organization.CostCode
534 [KTMTT] DEBUG [2008/07/28 22:51:22] | field-level type converter for
property [organization] = none found
535 [KTMTT] DEBUG [2008/07/28 22:51:22] | Property: costCode.organization
536 [KTMTT] DEBUG [2008/07/28 22:51:22] | Class:
com.ktm.tt.struts.action.organization.CreateCostCode
537 [KTMTT] DEBUG [2008/07/28 22:51:22] | global-level type converter for
property [organization] =
com.ktm.tt.struts.converters.organization.OrganizationConverter@2424c672
538 [KTMTT] ERROR [2008/07/28 22:51:22] | ParametersInterceptor -
[setParameters]: Unexpected Exception caught setting 'costCode.organization'
on 'class com.ktm.tt.struts.action.organization.CreateCostCode: Error
setting expression 'costCode.organization ' with value
'[Ljava.lang.String;@30fd981a'

So, what ends up happening is that the framework tries to determine the
conversion from a String to an Organization object... and fails.

I have the log levels jacked and I have _never_ seen the log statements I
have in place.

Any ideas??? 
-- 
View this message in context: http://www.nabble.com/custom-converter-takes-String-representation-of-long-ID-and-replaces-with-Object---convertFromString-not-being-called-tp18705754p18705754.html
Sent from the Struts - User mailing list archive at Nabble.com.


---------------------------------------------------------------------
To unsubscribe, e-mail: user-unsubscribe@struts.apache.org
For additional commands, e-mail: user-help@struts.apache.org


Re: custom converter takes String representation of long ID and replaces with Object - convertFromString not being called

Posted by Pierre Thibaudeau <pi...@gmail.com>.
2008/7/29 durbinjo593@gmail.com <du...@gmail.com>

> [...] First, might I make the assumption that type
> converters and validators can be represented as beans. Reason being is
> because I need to be able to do dependency injection via spring.


Converters as beans:  that's not a problem.  I have a similar setup with a
RegionConverter, and I inject the RegionDao inside the converter.  If you
use Spring 2.5 or above, you can use the following annotation (which is
infinitely handy)

import javax.annotation.Resource;
public class RegionConverter extends StrutsTypeConverter {
    @Resource(name = "regionDao") private RegionDao regionDao;
...
}

No need even for a setRegionDao() method!  It works great!  And the
definition of the Spring bean becomes merely:

<bean name="regionConverter"
class="com.mysite.locale.converters.RegionConverter" />

There again, no need to inject the reference to the "regionDao" bean! The
@Resource annotation does the work!

Now, as to the rest of your issue, I've never used ,properties files for
setting converters.  What if you tried with annotations?  Find the class
containing the property that requires a converter (usually it's the action,
but it could be the model if your action is ModelDriven).  Annotate that
class with @Conversion.  Then annotate the getter of that property with
@TypeConverter(converter = "beanName").  In my case, I have an action that
implements ModelDrive<User>, and here's an excerpt of what my User class
looks like:

import com.opensymphony.xwork2.conversion.annotations.Conversion;
import com.opensymphony.xwork2.conversion.annotations.TypeConversion;

@Conversion
public class User extends AbstractPersistentObject {
...
    private Region birthplace;

    @TypeConversion(converter = "regionConverter")
    public Region getBirthplace() { return birthplace; }
    public void setBirthplace(Region region) { this.birthplace = region; }
...
}


I hope that may help!