eclipse-ee4j / jaxb-ri

Jaxb RI
https://eclipse-ee4j.github.io/jaxb-ri/
BSD 3-Clause "New" or "Revised" License
205 stars 111 forks source link

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

Open Tomas-Kraus opened 18 years ago

Tomas-Kraus 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]

Tomas-Kraus commented 6 years ago
Tomas-Kraus commented 18 years ago

@glassfishrobot Commented Reported by mosh

Tomas-Kraus commented 18 years ago

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

Tomas-Kraus commented 18 years ago

@glassfishrobot Commented 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); }

}

Tomas-Kraus commented 17 years ago

@glassfishrobot Commented 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.

Tomas-Kraus commented 17 years ago

@glassfishrobot Commented rebeccas said: Implementation complete.

Tomas-Kraus commented 13 years ago

@glassfishrobot Commented 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).

Tomas-Kraus commented 12 years ago

@glassfishrobot Commented 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.

Tomas-Kraus commented 12 years ago

@glassfishrobot Commented 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.

Tomas-Kraus commented 7 years ago

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