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

Reply via email to