views:

642

answers:

2

How can I keep my using interfaces in classes I want to use JiBX binding with?

Example: I have this very simple model in java:

public interface A {
    B getB();
    void setB(B b);
}

public interface B {
    String getData();
    void setData(String data);
}

public class AImpl implements A {
    B b;

    @Override
    public B getB() {
        return b;
    }

    @Override
    public void setB(B b) {
        this.b = b;     
    }
}

public class BImpl implements B {
    private String data;
    @Override
    public String getData() {
        return data;
    }

    @Override
    public void setData(String data) {
        this.data = data;
    }
}

And this binding document:

When I try to run my code I get this exception:

java.lang.ClassFormatError: Method in class com/test/B has illegal modifiers: 0x1001

I've tried to use 'abstract="true"' on both mapping, only to get this exception:

...Caused by: org.jibx.runtime.JiBXException: Unable to access binding information for class com.test.A Make sure the binding has been compiled...

The only solution I've found is to have AImpl hold a BImpl instead of a B, and have the getter return BImpl and the setter recieve BImpl. This is very wrong as it breaks the interface completely.

How can I solve this? I've been pulling hairs out, having tantrums (the real issue is much more complex, and JiBX cryptic error messages don't help) - nothing help.

Is this solvable? Is JiBX really that intrusive (in that it requires me to abandon all interface programming?)

Please don't answer "use AbstractB" as it's the same problem, only one level removed.

+3  A: 

In the mapping, you should be able use the "create-type" attribute to specify the concrete class that JiBX should instantiate for bean properties that have an interface type. I use this a lot for collection properties. For example, you can tell JiBX to instantiate a java.util.HashSet for a property of type java.util.Set. But I believe it works just as well for non-collection properties. Your mapping would look something like:

<mapping class="com.mypackage.AImpl" name="A">
  <structure get-method="getB" set-method="setB" create-type="com.mypackage.BImpl">
    ...
  </structure>
  ...
</mapping>

JiBX will call the no-arg constructor to create the B object. Alternatively, you could use a factory or a custom serializer/deserializer if you need fancy instantiation logic. See this reference page for details.

Rob H
Great answer, one correction - the create-type should be on the mapping of B, not on the structure (at least in the presented case). Amazing how many hours I've been circling the problem without seeing it. You have just made my work sane again :)
Ran Biron
A: 

Another good resource is the binding.dtd - apparently it's not in the distribution but can be downloaded from here: http://jibx.cvs.sourceforge.net/viewvc/checkout/jibx/core/docs/binding.dtd. Put this file somewhere (c:\binding.dtd for example). Then, in the top binding entry, use this:

<binding xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="file://jibx/binding.dtd">

and register file://jibx/binding.dtd to point to your saved binding.dtd for documentation and verification goodies.

It's amazing what inertia does - I know that xml files should have schemas / dtds, I've used them before and always said "without a schema understanding this would've been impossible". Yet when I've entered this project, it never occurred to me to search for the schema / dtd for this xml - I just accepted it as given that it had none.
Lesson learned.

Ran Biron