Hi Keith,
I think I got your point now. Chris is using the Handler for object creation only. That's why he still needs the other mapping.
Well, in that case, maybe the code really needs a fix...
Thanks for the explanation.
Matthias.
-----Original Message-----
From: Keith Visco [mailto:[EMAIL PROTECTED]]
Sent: Wednesday, December 18, 2002 9:56 AM
To: [EMAIL PROTECTED]
Subject: Re: [castor-dev] NotConstructable Exception and FieldHandler
Hi Matthias,
The problem that Chris' example highlights is when using a special FieldHandler (or even a simple create-method) to create an object whose class doesn't have a default constructor then one isn't able to specify the mapping for that object. Your example works well because you are converting a string value to something complex for your object model, so you don't have to worry about the mapping it's just a simple string as far as Castor is concerend because you are abstracting the complexities from Castor. Chris on the other hand is basically using the FieldHandler as a simple factory to create his instance object and expects Castor to populate the fields. This is a valid use of the FieldHandler since his Class has all the proper getter/setter methods. The only issue is that Castor then complains that the Class is not constructable even though Castor doesn't need to construct it, because the handler does it.
It's a bit difficult to explain and I hope I haven't confused you or anyone else reading this. Anyway I do believe Chris' example is a valid one.
--Keith
> Matthias David wrote:
>
> Hi Keith,
>
> I think it's up to the developer to delete a mapping for a class that
> is mapped in a field by a FieldHandler. The mapping is not needed
> anymore if I have a FieldHandler for that class. Or why would I
> implement the FieldHandler then?
>
> So in my opinion there's no need to change anything in the current
> Unmarshaller code. Just make a hint in the current FieldHandler and
> XML-mapping docs.
>
> Matthias.
>
> -----Original Message-----
> From: Keith Visco [mailto:[EMAIL PROTECTED]]
> Sent: Wednesday, December 18, 2002 9:19 AM
> To: [EMAIL PROTECTED]
> Subject: Re: [castor-dev] NotConstructable Exception and FieldHandler
>
> Hi Chris
>
> One workaround to the issue of not-constructable is to use an
> interface or abstract class as such:
>
> public interface IPet {
>
> public int getAge();
> public String getName();
>
> public void setAge(int age);
> public void setName(String name);
> }
>
> And then have your Pet class implement the interface (or extend the
> abstract class):
>
> public class Pet implements IPet {
>
> }
>
> And then use IPet in the mapping file instead of Pet as such:
>
> <class name="IPet">
>
> <field name="name" type="java.lang.String">
> <bind-xml name="name" node="attribute" />
> </field>
>
> <field name="age" type="java.lang.Integer">
> <bind-xml name="age" node="attribute" />
> </field>
> </class>
>
> I know it's a pain to have to do that...but it's only a work-around to
> allow the specification of your Pet class without having to rely on
> default introspection.
>
> I'll try to look at the default constructor and see if I can write a
> by-pass for that. In most cases we want to throw the exception because
> people expect Castor to create the instance of the class, but in your
> case Castor won't be creating the instance so it makes sense not to
> throw the exception. There are a couple quick solutions I can think
> of:
>
> 1. Remove the mapping restriction and let it be a runtime
> unmarshalling error.
>
> 2. Provide a way in the mapping file to specify that the class won't
> need to be created by
> Castor and therefore it doesn't matter if it's not constructable
> with zero args.
>
> Also we could possibly check that all occurances of fields that use
> the "Pet" class provide their own handler or create Method and if so
> throw no exception. This would take a bit longer to implement but
> might be the better solution.
>
> --Keith
>
> Keith Visco wrote:
> >
> > Hi Chris,
> >
> > I got it to work by simply commenting out the class mapping for Pet
> as
> > such:
> >
> > <!--
> > <class name="Pet">
> > <map-to xml="pet" />
> >
> > <field name="name" type="java.lang.String">
> > <bind-xml name="name" node="attribute" />
> > </field>
> >
> > <field name="age" type="java.lang.Integer">
> > <bind-xml name="age" node="attribute" />
> > </field>
> > </class>
> > -->
> >
> > and letting Castor introspect the class.
> >
> > The MappingLoader doesn't like the fact the the Pet class doesn't
> have
> > a default (no arg) constructor.
> >
> > I'll have to look into removing that limitation from the
> > MappingLoader.
> >
> > --Keith
> >
> > Chris Bedford wrote:
> > >
> > > Keith:
> > >
> > > I apologize for being thick, but I'm still lost on this one...
> > >
> > > I have created a real simple example that tries to follow your
> > > advice to Matthias of setting the type of the object that the
> > > handler is expecting to receive..... in my case I assume its not
> a
> > > string (but I'm not 100% sure)...
> > >
> > > I'd be much obliged if you could you clue me in on what I'm
> messing
> > > up in the code below -> (the listing is a bit long, but its a
> simple
> > > unmarshal/marshal of this xml ->
> > >
> > > <person name="Bob" age="44">
> > > <pet name="spot" age="2"/>
> > > </person>
> > >
> > > ////////////////// mapping.xml
> > >
> > > <!DOCTYPE mapping PUBLIC "-//EXOLAB/Castor Object Mapping DTD
> > > Version 1.0//EN" "http://castor.exolab.org/mapping.dtd">
> > > <mapping>
> > > <class name="Person">
> > > <map-to xml="person" />
> > >
> > > <field name="name" type="java.lang.String">
> > > <bind-xml name="name" node="attribute" />
> > > </field>
> > >
> > > <field name="age" type="java.lang.Integer">
> > > <bind-xml name="age" node="attribute" />
> > > </field>
> > >
> > > <field name="pet" type="Pet" handler="Handler">
> > > <bind-xml name="pet" node="element"/>
> > > </field>
> > > </class>
> > >
> > > <class name="Pet">
> > > <map-to xml="pet" />
> > >
> > > <field name="name" type="java.lang.String">
> > > <bind-xml name="name" node="attribute" />
> > > </field>
> > >
> > > <field name="age" type="java.lang.Integer">
> > > <bind-xml name="age" node="attribute" />
> > > </field>
> > > </class>
> > > </mapping>
> > >
> > > /////////////// FieldHandlerDemo.java
> > > import org.exolab.castor.mapping.Mapping;
> > > import org.exolab.castor.mapping.MappingException;
> > >
> > > import org.exolab.castor.xml.Unmarshaller;
> > > import org.exolab.castor.xml.Marshaller;
> > >
> > > import java.io.IOException;
> > > import java.io.FileReader;
> > > import java.io.OutputStreamWriter;
> > >
> > > import org.xml.sax.InputSource;
> > >
> > > public class FieldHandlerDemo {
> > >
> > > public static void main(String args[]) {
> > >
> > > Mapping mapping = new Mapping();
> > >
> > > try {
> > > // 1. Load the mapping information from the file
> > > mapping.loadMapping( "mapping.xml" );
> > >
> > > // 2. Unmarshal the data
> > > Unmarshaller unmar = new Unmarshaller(mapping);
> > > Person person = (Person)unmar.unmarshal(new
> > > InputSource(new
> > > FileReader("person.xml")));
> > >
> > > // 3. Do some processing on the data
> > > person.setName("Frank");
> > >
> > > // 4. marshal the data with the total price back and
> > > print the XML in the console
> > > Marshaller marshaller = new Marshaller(new
> > > OutputStreamWriter(System.out));
> > > marshaller.setMapping(mapping);
> > > marshaller.marshal(person);
> > > System.out.println("");
> > >
> > > } catch (Exception e) {
> > > System.out.println(e);
> > > return;
> > > }
> > > }
> > > }
> > >
> > > public class Pet {
> > > private int age;
> > > private String name;
> > >
> > >
> //////////////////////////////////////////////////////////////////////
>
> > > // Getters
> > >
> > > public int getAge()
> > > {
> > > return age;
> > > }
> > >
> > > public String getName()
> > > {
> > > return name;
> > > }
> > >
> > >
> //////////////////////////////////////////////////////////////////////
>
> > > // Setters
> > >
> > > public void setAge(int age)
> > > {
> > > this.age = age;
> > > }
> > >
> > > public void setName(String name)
> > > {
> > > this.name = name;
> > > }
> > >
> > >
> //////////////////////////////////////////////////////////////////////
>
> > > // Constructors
> > >
> > > Pet(int age, String name) {
> > > this.age = age;
> > > this.name = name;
> > > }
> > >
> > > }
> > >
> > > public class Person {
> > >
> > > private Pet pet;
> > > private String name;
> > > private int age;
> > >
> > >
> //////////////////////////////////////////////////////////////////////
>
> > > // Getters
> > >
> > > public Pet getPet()
> > > {
> > > return pet;
> > > }
> > >
> > > public int getAge()
> > > {
> > > return age;
> > > }
> > >
> > > public String getName()
> > > {
> > > return name;
> > > }
> > >
> > >
> //////////////////////////////////////////////////////////////////////
>
> > > // Setters
> > >
> > > public void setPet(Pet pet)
> > > {
> > > this.pet = pet;
> > > }
> > >
> > > public void setAge(int age)
> > > {
> > > this.age = age;
> > > }
> > >
> > > public void setName(String name)
> > > {
> > > this.name = name;
> > > }
> > >
> > > }
> > >
> > > ///////// Handler.java
> > > import org.exolab.castor.mapping.*;
> > >
> > > public class Handler implements FieldHandler {
> > > public Object newInstance(Object parent) throws
> IllegalStateException {
> > > System.out.println("newInstance called");
> > > return new Pet(0, "dummy");
> > > }
> > >
> > > public Object getValue(Object object) throws
> IllegalStateException {
> > > return ((Person)object).getPet();
> > > }
> > >
> > > public void setValue(Object object, Object value)
> > > throws
> > > IllegalStateException, IllegalArgumentException {
> > > Person person = (Person) object;
> > > Pet petVal = (Pet) value;
> > > person.setPet(petVal);
> > > }
> > >
> > > public void resetValue(Object object) throws
> > > IllegalStateException, IllegalArgumentException {
> > > }
> > >
> > > public void checkValidity(Object object) throws
> ValidityException,
> > > IllegalStateException {
> > > }
> > > }
> > >
> > > ----- Original Message -----
> > > From: "Keith Visco" <[EMAIL PROTECTED]>
> > > To: <[EMAIL PROTECTED]>
> > > Sent: Monday, December 16, 2002 1:10 PM
> > > Subject: Re: [castor-dev] NotConstructable Exception and
> > > FieldHandler
> > >
> > > >
> > > > Change you mapping to the following:
> > > >
> > > > <class name="com.Coordinates" access="shared">
> > > > <description>Default mapping for
> Coordinates</description>
> > > > <map-to xml="Coordinates"/>
> > > > <field name="format" type="string"
> > > > handler="com.CoordinateFormatEnumFieldHandler">
> > > > <bind-xml name="Format" node="attribute"/>
> > > > </field>
> > > > </class>
> > > >
> > > > Note that I changed the "type" to "string" instead of
> > > > "com.CoordinateFormatEnum". When using a handler you need to
> > > > specify the type that the handler is expecting to recieve in a
> > > > call to the setObject and returns in a call to the getObject.
> > > >
> > > > --Keith
> > > >
> > > > > Matthias David wrote:
> > > > >
> > > > > Hi,
> > > > >
> > > > > I have written a FieldHandler for a class
> (CoordinateFormatEnum)
> > > > > that has no public constructor. When Unmarshalling I get the
> > > > > following
> > > > > exception:
> > > > >
> > > > > Nested error: org.exolab.castor.mapping.MappingException: The
> > > > > Java class CoordinateFormatEnum is not constructable -- it
> does
> > > > > not contain a default public constructor)
> > > > >
> > > > > The problem is that the class CoordinateFormatEnum is a
> > > > > tool-generated class, so I have no chance to make the
> > > > > constructor public. So How can this problem be solved? I
> thought
> > > > > that the Unmarshaller does not need to call the constructor of
>
> > > > > the class since the FieldHandler is responsible for that, e.g.
>
> > > > > using the method "newInstance".
> > > > >
> > > > > Here's the handler's code:
> > > > >
> > > > > public class CoordinateFormatEnumFieldHandler implements
> > > > > FieldHandler {
> > > > >
> > > > > public Object getValue(Object object)
> > > > > throws IllegalStateException {
> > > > > return ((Coordinates)object).getFormat().getValue();
> > > > > }
> > > > >
> > > > > public void setValue(Object object, Object value)
> > > > > throws IllegalStateException,
> > > > > IllegalArgumentException {
> > > > >
> > > > >
> > >
> ((Coordinates)object).setFormat(CoordinateFormatEnum.fromString((Str
> > > ing)valu
> > > e));
> > > > >
> > > > > }
> > > > >
> > > > > public void resetValue(Object object)
> > > > > throws IllegalStateException,
> IllegalArgumentException {
> > > > > }
> > > > >
> > > > > public void checkValidity(Object object)
> > > > > throws ValidityException, IllegalStateException {
> > > > > }
> > > > >
> > > > > public Object newInstance(Object parent)
> > > > > throws IllegalStateException {
> > > > > return CoordinateFormatEnum.Mercator;
> > > > > }
> > > > > }
> > > > >
> > > > > And here's the mapping:
> > > > >
> > > > > <class name="com.Coordinates" access="shared">
> > > > > <description>Default mapping for
> Coordinates</description>
> > > > > <map-to xml="Coordinates"/>
> > > > > <field name="format" type="com.CoordinateFormatEnum"
> > > > > handler="com.CoordinateFormatEnumFieldHandler">
> > > > > <bind-xml name="Format" node="attribute"/>
> > > > > </field>
> > > > > </class>
> > > > >
> > > > > Any clues for that?
> > > > >
> > > > > Thanks,
> > > > > Matthias.
> > > >
> > > > -----------------------------------------------------------
> > > > If you wish to unsubscribe from this mailing, send mail to
> > > > [EMAIL PROTECTED] with a subject of: unsubscribe castor-dev
> > > >
> > >
> > > -----------------------------------------------------------
> > > If you wish to unsubscribe from this mailing, send mail to
> > > [EMAIL PROTECTED] with a subject of:
> > > unsubscribe castor-dev
> >
> > -----------------------------------------------------------
> > If you wish to unsubscribe from this mailing, send mail to
> > [EMAIL PROTECTED] with a subject of:
> > unsubscribe castor-dev
>
> -----------------------------------------------------------
> If you wish to unsubscribe from this mailing, send mail to
> [EMAIL PROTECTED] with a subject of:
> unsubscribe castor-dev
-----------------------------------------------------------
If you wish to unsubscribe from this mailing, send mail to [EMAIL PROTECTED] with a subject of:
unsubscribe castor-dev
