javaee / jaxb-v2

Other
211 stars 99 forks source link

Getter and Setter can't be in different class in the hierarchy #251

Open glassfishrobot opened 18 years ago

glassfishrobot commented 18 years ago

The problem Im having is that JAXB doesnt recognize a setter for a property if the setter parameter is a not exactly of the same as the parameter of the getter but rather a "parent-class".

for Example, when i have the following classes:

class A{ }

class B extends A{ A parent; void setParent(A parent)

{...} abstract A getParent();

}

class C extends B{ @XMLIDREF B getParent(){...}

}

JAXB doesnt recognize the setter inside A as the right setter for "parent".

After going over the JAXB source code i found that the cause is that ClassInfoImpl.collectGetterSetters() method has the following code:

========================= for (M setter : propSetters) { T setterType = nav().getMethodParameters(setter)[0]; if (setterType.equals(getterType)) { setters.put(propName, setter); break; } }

Since setterType.equals(getterType)==false, JAXB wont find setParent() as a setter.

Environment

Operating System: All Platform: All URL: http://forums.java.net/jive/thread.jspa?threadID=18616&tstart=0

Affected Versions

[2.1]

glassfishrobot commented 18 years ago

Reported by mosh

glassfishrobot commented 17 years ago

kohsuke said: I think this issue has been fixed some time ago.

glassfishrobot commented 17 years ago

mosh said: I dont think so. At leat not with the version from 18/10/2006. Look at the the following code at ClassInfoImp.java:

// Match getter with setters by comparing getter return type to setter param for (Map.Entry<String,M> entry : getters.entrySet()) { String propName = entry.getKey(); M getter = entry.getValue(); List propSetters = allSetters.remove(propName); if (null == propSetters)

{ //no matching setter continue; }

allSetters is only from this class and not from its super-classes (unless the super-class is @XmlTransient).

I've created a function that also seeks for setters in the super-class. I can submit it as a patch. What is the procedure?

Thanks! Mosh

//////////////////////////////////// // This is the method BTW:

List findSetterInSuperClass(C c, String propName){ List propSetters = null;

Collection<? extends M> methods = nav().getDeclaredMethods(c); for( M method : methods ) { if(nav().isBridgeMethod(method)) continue; // ignore

String name = nav().getMethodName(method); int arity = nav().getMethodParameters(method).length;

// TODO - is needed???? if(nav().isStaticMethod(method))

{ ensureNoAnnotation(method); continue; }

// is this a set method? String propNameFromSetter = getPropertyNameFromSetMethod(name); if(propNameFromSetter!=null && arity==1) { if(propNameFromSetter.equals(propName)){ if(propSetters == null)

{ propSetters = new ArrayList(); }

propSetters.add(method); } } }

if(propSetters != null)

{ return propSetters; }

else

{ // If we havent found the getter - going up to its super-class C sc = nav().getSuperClass(c); if((sc==null) || (sc==Object.class)) return null; else return findSetterInSuperClass(sc,propName); }

}

glassfishrobot commented 17 years ago

kohsuke said: Yes, if you can provide us a patch, that would be great!

See https://glassfish.dev.java.net/public/GovernancePolicy.html#SCA_Policy and please send us the SCA so that we can accept a patch. Otherwise, just go create a patch and post the diff to the issue please.

You'll only need to make sure that the patch will work for you. We'll run it through the tests on our side as well.

glassfishrobot commented 17 years ago

rebeccas said: Implementation complete.

glassfishrobot commented 13 years ago

desruisseaux said: Is this improvement really done? I tried the following code snippet. It work well if the argument type of the setValue method is Double, but doesn't work anymore if I relax it to Number:

import java.io.*;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.annotation.*;

@XmlRootElement
public class SetterWithParentClass {
    private double value;

    @XmlElement
    public Double getValue() {
        return value;
    }

    // Argument type should be Double - testing with a relaxed type.
    public void setValue(Number n) {
        value = n.doubleValue();
    }

    public static void main(String[] args) throws Exception {
        JAXBContext c = JAXBContext.newInstance(SetterWithParentClass.class);
        SetterWithParentClass test = new SetterWithParentClass();
        test.value = 3;
        StringWriter out = new StringWriter();
        c.createMarshaller().marshal(test, out);
        String xml = out.toString();
        System.out.println(xml);

        // Unmarshall
        StringReader in = new StringReader(xml);
        test = (SetterWithParentClass) c.createUnmarshaller().unmarshal(in);
        System.out.println("value = " + test.value);
    }
}

Output is (adding indentation for clarity):

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<setterWithParentClass>
  <value>3.0</value>
</setterWithParentClass>

value = 0.0

I would have hopped a value of 3.0, as we get when the setter method is setValue(Double).

glassfishrobot commented 12 years ago

yaroska said: I think this is not a valid issue.

If JAXB is working with JavaBeans-style classes its expected that properties should have getters and setters of the same type. Which is not true in this case.

glassfishrobot commented 12 years ago

desruisseaux said: This issue is not incompatible with JavaBeans-style classes. It is a relaxed interpretation - not everyone want the JavaBeans constraints. In my case, I have about 100 classes derived from the ISO 19115 international standard, and I would like to design the API for ease of use rather than JAXB constraints. In its current form, the API forces the users to perform themselves a lot of wrapping toward some specialized interfaces (InternationalString - which is specific to the project) while the setters could accept a more generic interface (CharSequence - which would allow the users to specify a plain String) and do the wrapping themselves.

If the JavaBeans restriction is still considered necessary, some annotation allowing us to specify that a method is the setter of a property would be appreciated. Maybe we could reuse the current tt>@Element</tt annotation, which would be allowed to be applied to setter methods.

An alternative is to declare setter methods twice: one JavaBeans-compliant method and one convenience method. But this approach bloat the API and binary file for few purpose. I currently don't do that since I think it would bloat too much a collection of classes of the size of ISO 19115.

glassfishrobot commented 7 years ago

This issue was imported from java.net JIRA JAXB-251