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((String)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