highsource / jaxb2-basics

Useful plugins and tools for JAXB2.
BSD 2-Clause "Simplified" License
109 stars 54 forks source link

wrong place with simplify plugin #3

Closed yinan-liu closed 10 years ago

yinan-liu commented 10 years ago

The issue is about the simplify plugin.

When I tried to give a maven build on the project, I got exception "compiler was unable to honor this as-element-property customization. It is attached to a wrong place, or its inconsistent with other bindings" whenever the simplify customization was put on choice or element inside the choice.

Here is my schema

 <?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified" attributeFormDefault="unqualified"  xmlns="http://www.aaa.com/00" targetNamespace="http://www.aaa.com/00" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://java.sun.com/xml/ns/jaxb http://java.sun.com/xml/ns/jaxb/bindingschema_2_0.xsd"  xmlns:simplify="http://jaxb2-commons.dev.java.net/basic/simplify" xmlns:jaxb="http://java.sun.com/xml/ns/jaxb" jaxb:extensionBindingPrefixes="simplify">  <xs:complexType name="OpTimesAndDur">   <xs:sequence>   <xs:element name="OpTimeDur" minOccurs="0" maxOccurs="50">   <xs:complexType>         <xs:sequence>  <xs:element name="TimeCat" type="xs:string" minOccurs="1" maxOccurs="1" />            <xs:choice minOccurs="1" maxOccurs="1">  <xs:element name="Time" type="xs:dateTime" minOccurs="1" maxOccurs="1">  <xs:annotation>    <xs:appinfo>   <simplify:as-element-property />                  </xs:appinfo>   </xs:annotation>   </xs:element>    <xs:element name="Duration" type="xs:duration" minOccurs="1" maxOccurs="1" />   </xs:choice>   </xs:sequence>   </xs:complexType>     </xs:element>    </xs:sequence>  </xs:complexType></xs:schema>
highsource commented 10 years ago

Sorry, the schema is not readable. Please format using markdown or use pastebin&likes to post the code.

yinan-liu commented 10 years ago

now it s better.

highsource commented 10 years ago

Hm. I'm not getting it. What do you want to simplify, actually? I don't see any heterogeneous properties. This is what I get and there's nothing to simplify there:

@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "OperationTimesAndDurationsType", propOrder = {
    "operationTimeDuration"
})
public class OperationTimesAndDurationsType {

    @XmlElement(name = "OperationTimeDuration")
    protected List<OperationTimesAndDurationsType.OperationTimeDuration> operationTimeDuration;

    /**
     * Gets the value of the operationTimeDuration property.
     * 
     * <p>
     * This accessor method returns a reference to the live list,
     * not a snapshot. Therefore any modification you make to the
     * returned list will be present inside the JAXB object.
     * This is why there is not a <CODE>set</CODE> method for the operationTimeDuration property.
     * 
     * <p>
     * For example, to add a new item, do as follows:
     * <pre>
     *    getOperationTimeDuration().add(newItem);
     * </pre>
     * 
     * 
     * <p>
     * Objects of the following type(s) are allowed in the list
     * {@link OperationTimesAndDurationsType.OperationTimeDuration }
     * 
     * 
     */
    public List<OperationTimesAndDurationsType.OperationTimeDuration> getOperationTimeDuration() {
        if (operationTimeDuration == null) {
            operationTimeDuration = new ArrayList<OperationTimesAndDurationsType.OperationTimeDuration>();
        }
        return this.operationTimeDuration;
    }

    /**
     * <p>Java class for anonymous complex type.
     * 
     * <p>The following schema fragment specifies the expected content contained within this class.
     * 
     * <pre>
     * &lt;complexType>
     *   &lt;complexContent>
     *     &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
     *       &lt;sequence>
     *         &lt;element name="TimeType" type="{http://www.w3.org/2001/XMLSchema}string"/>
     *         &lt;choice>
     *           &lt;element name="Time" type="{http://www.w3.org/2001/XMLSchema}dateTime"/>
     *           &lt;element name="Duration" type="{http://www.w3.org/2001/XMLSchema}duration"/>
     *         &lt;/choice>
     *       &lt;/sequence>
     *     &lt;/restriction>
     *   &lt;/complexContent>
     * &lt;/complexType>
     * </pre>
     * 
     * 
     */
    @XmlAccessorType(XmlAccessType.FIELD)
    @XmlType(name = "", propOrder = {
        "timeType",
        "time",
        "duration"
    })
    public static class OperationTimeDuration {

        @XmlElement(name = "TimeType", required = true)
        protected String timeType;
        @XmlElement(name = "Time")
        @XmlSchemaType(name = "dateTime")
        protected XMLGregorianCalendar time;
        @XmlElement(name = "Duration")
        protected Duration duration;

        /**
         * Gets the value of the timeType property.
         * 
         * @return
         *     possible object is
         *     {@link String }
         *     
         */
        public String getTimeType() {
            return timeType;
        }

        /**
         * Sets the value of the timeType property.
         * 
         * @param value
         *     allowed object is
         *     {@link String }
         *     
         */
        public void setTimeType(String value) {
            this.timeType = value;
        }

        /**
         * Gets the value of the time property.
         * 
         * @return
         *     possible object is
         *     {@link XMLGregorianCalendar }
         *     
         */
        public XMLGregorianCalendar getTime() {
            return time;
        }

        /**
         * Sets the value of the time property.
         * 
         * @param value
         *     allowed object is
         *     {@link XMLGregorianCalendar }
         *     
         */
        public void setTime(XMLGregorianCalendar value) {
            this.time = value;
        }

        /**
         * Gets the value of the duration property.
         * 
         * @return
         *     possible object is
         *     {@link Duration }
         *     
         */
        public Duration getDuration() {
            return duration;
        }

        /**
         * Sets the value of the duration property.
         * 
         * @param value
         *     allowed object is
         *     {@link Duration }
         *     
         */
        public void setDuration(Duration value) {
            this.duration = value;
        }

    }

}
highsource commented 10 years ago

Should maybe maxOccurs be unbounded on the xs:choice?

BTW is this a public or proprietary schema?

yinan-liu commented 10 years ago

It is a proprietary schema.

Sorry, my requirement was not very clear, it is a little difficult to explain. Actually we have several xs:choice in our schema, and we use choiceContentProperty="true" in the xjb binding file to make the dto class have one single attribute generated for the element inside the choice, but with lagacy code I would like to keep the backward compatibility, so I just only want to keep Time and Duration element separated as two attributes. That s the initial story, and that s why I found the simplify plugin and gave a try.

I tried to use xjb binding file to generate what I want as my question here http://stackoverflow.com/questions/26523990/jaxb-simplify-plugin-still-usable

here was I used

<jaxb:bindings node="//xs:complexType[@name='Op']//xs:choice/xs:element[@name='Time']"> <simplify:as-element-property/></jaxb:bindings>

but it failed because of the same exception "wrong place ...."

voila the whole story, can you advise me if it is possible please

highsource commented 10 years ago

Ok, I'll then anonymize it in an example.

The problem why it is failing is that in your example you don't have a property to simplify. Check the snippet above, there's no complex/heterogeneous property. time and duration are already separate. Nothing to simplify - the plugin does nothing - your cutomization is not "consumed" - you get an error.

The question is, why are your trying to simplify what ist already not complex? Can you show me what do you get generated in this case? Do you get a timeOrDuration property? Because I don't.

yinan-liu commented 10 years ago

Yes, i do have a timeOrDuration property, as JAXBElement<?> type.

with this config as I mentioned previously " choiceContentProperty="true" " as global setting in the binding file

highsource commented 10 years ago

The schema you have provided does not generate this property for me. Please make sure it's not missing anything.

yinan-liu commented 10 years ago

did you set " choiceContentProperty="true" " in global setting in the xjb binding file. I got this

@XmlElementRefs({ @XmlElementRef(name = "Duration", type = JAXBElement.class, required = false), @XmlElementRef(name = "Time", type = JAXBElement.class, required = false) }) protected JAXBElement<?> timeOrDuration;

highsource commented 10 years ago

Ok, so we also need the bindings file.

highsource commented 10 years ago

Ok, I got this:

        @XmlElements({
            @XmlElement(name = "Time", type = XMLGregorianCalendar.class),
            @XmlElement(name = "Duration", type = Duration.class)
        })
        protected Object timeOrDuration;

Not with references, but close.

highsource commented 10 years ago

Sorry, it did not work. No error but also no effect.

Would you please provide schema and binding files which produce @XmlElementRefs-property like in your case?

Please test with:

xjc schema.xsd -b binding.xjb

(I can't correct what I can't reproduce.)

yinan-liu commented 10 years ago

Due to lots of elements, i have to modify a bit the binding file, and the schema. here is the binding file

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<jaxb:bindings xmlns:jaxb="http://java.sun.com/xml/ns/jaxb" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xjc="http://java.sun.com/xml/ns/jaxb/xjc" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/jaxb http://java.sun.com/xml/ns/jaxb/bindingschema_2_0.xsd" version="2.1">
    <jaxb:globalBindings generateElementProperty="false" generateIsSetMethod="true" fixedAttributeAsConstantProperty="true" choiceContentProperty="true">  
    </jaxb:globalBindings>
</jaxb:bindings>

with which i got the same as yours

highsource commented 10 years ago

Ok, so we'll concentrate on th @XmlElements property.

I don't get an error when I customize xs:elements, but there's also no effect.

This looks like a but, I'll take care of it.

You could help by providing an "anonymized" schema so that we both don't get in legal trouble.

yinan-liu commented 10 years ago
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified" attributeFormDefault="unqualified"
  xmlns="http://www.anonym.com/00" targetNamespace="http://www.anonym.com/00" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://java.sun.com/xml/ns/jaxb http://java.sun.com/xml/ns/jaxb/bindingschema_2_0.xsd"
  xmlns:simplify="http://jaxb2-commons.dev.java.net/basic/simplify" xmlns:jaxb="http://java.sun.com/xml/ns/jaxb"
  jaxb:extensionBindingPrefixes="simplify">
  <xs:complexType name="ParentsType">
    <xs:sequence>
      <xs:element name="parent" minOccurs="0" maxOccurs="50">
        <xs:complexType>
          <xs:sequence>
            <xs:element name="type1" type="xs:string" minOccurs="1" maxOccurs="1" />
            <xs:choice minOccurs="1" maxOccurs="1">
              <xs:element name="type2" type="xs:dateTime" minOccurs="1" maxOccurs="1">
              </xs:element>
              <xs:element name="type3" type="xs:duration" minOccurs="1" maxOccurs="1" />
            </xs:choice>
          </xs:sequence>
        </xs:complexType>
      </xs:element>
    </xs:sequence>
  </xs:complexType>
</xs:schema>
highsource commented 10 years ago

Thank you for the schema, reproduced, added as test.

highsource commented 10 years ago

There were a few problems.

One was that the plugin only checked for the collection properties.

The other one is that somehow XJC does not consider customizations on choiceContentProperty. At all. So basically you can't customize this property. Therefor my plugin did not work at all.

The solution which I have implemented now is that instead of customizing the property with

<simplify:as-element-property/>

you can now customize the class with

<simplify:property name="type2OrType3">
    <simplify:as-element-property/>
</simplify:property>

Please see this bindings file for example.

You can checkout/build/test the latests snapshot to check if it works for you.

This development is not yet finished, as I have to implement more tests and document. Please don't close the issue.

yinan-liu commented 10 years ago

Great, thank you for your effort, and i will try your solution today and tell you the result.

yinan-liu commented 10 years ago

Ok, I confirm that the customization is working now with the latest snapshot code. thx again, and waiting for your release.

highsource commented 10 years ago

Thanks for the feedback. Release-timeline is ca. 1 week.

On Mon, Oct 27, 2014 at 11:01 AM, yinan-liu notifications@github.com wrote:

Ok, I confirm that the customization is working now with the latest snapshot code. thx again, and waiting for your release.

— Reply to this email directly or view it on GitHub https://github.com/highsource/jaxb2-basics/issues/3#issuecomment-60570534 .

yinan-liu commented 10 years ago

Is the fix released in the new version ? 0.9.0 ?

highsource commented 10 years ago

No, not yet. Only fully fixed - with tests and documentation. I'm planning to release on the weekend.

On Wed, Oct 29, 2014 at 10:17 AM, yinan-liu notifications@github.com wrote:

Is the fix released in the new version ?

— Reply to this email directly or view it on GitHub https://github.com/highsource/jaxb2-basics/issues/3#issuecomment-60893190 .

yinan-liu commented 10 years ago

Sorry, but i just realized an issue, hope this will only be a little trick of config. Did you notice that in the xsd sample I gave, the element type2 is a dateTime type, which will be converted into Date type by a adapter defined in the binding file which i did not put in the example. With the fix, I do have the time as separated attribute, but the type is a String. Do you think the plugin can be used combined with a customer adapter ? Really sorry I did not realize it earlier.

highsource commented 10 years ago

Could you please send me a pull request for https://github.com/highsource/jaxb2-basics/blob/master/tests/simplify-01/src/main/resources/schema.xsd which would add the adapter configuration?

I think adapters should be possible, but it has to be implemented and tested carefully.

On Wed, Oct 29, 2014 at 10:54 AM, yinan-liu notifications@github.com wrote:

Sorry, but i just realized an issue, hope this will only be a little trick of config. Did you notice that in the xsd sample I gave, the element type2 is a dateTime type, which will be converted into Date type by a adapter defined in the binding file which i did not put in the example. With the fix, I do have the time as separated attribute, but the type is a String. Do you think the plugin can be used combined with a customer adapter ? Really sorry I did not realize it earlier.

— Reply to this email directly or view it on GitHub https://github.com/highsource/jaxb2-basics/issues/3#issuecomment-60897196 .

yinan-liu commented 10 years ago

I didn't get you. What we do to parse the dateTime to Date is in binding file like

<jaxb:globalBindings generateElementProperty="false" generateIsSetMethod="true" fixedAttributeAsConstantProperty="true" choiceContentProperty="true">
    <!-- Use java.util.Date instead of javax.xml.datatype.XMLGregorianCalendar for xs:dateTime -->
    <jaxb:javaType name="java.util.Date" xmlType="xs:dateTime" parseMethod="com.presentation.model.Adapter.DateAdapter.parseDateTime" printMethod="com.presentation.model.Adapter.DateAdapter.printDateTime"/>
    <!-- Force all classes implements Serializable -->
    <xjc:serializable uid="1"/>
</jaxb:globalBindings>

the DateAdapter class is

import java.util.Date;

import org.joda.time.DateTime;
import org.joda.time.format.DateTimeFormatter;
import org.joda.time.format.ISODateTimeFormat;

/**
 * 
 * 
 * @author
 */
public class DateAdapter {

  private static final DateTimeFormatter s_parser = ISODateTimeFormat.dateTimeParser().withZoneUTC();
  private static final DateTimeFormatter s_formatter = ISODateTimeFormat.dateTime().withZoneUTC();

  public static Date parseDateTime(String v) {

    try {
      return s_parser.parseDateTime(v).toDate();
    }
    catch (Exception e) {
      return null;
    }

  }

  /** {@inheritDoc} */

  public static String printDateTime(Date v) {
    return new DateTime(v).toString(s_formatter);
  }

So in your xsd the part of

<xs:complexType name="gh2">
    <xs:sequence>
        <xs:element name="a" type="xs:string"/>
        <xs:choice>
            <xs:element name="b" type="xs:dateTime"/>
            <xs:element name="c" type="xs:duration"/>
        </xs:choice>
    </xs:sequence>
</xs:complexType>

the element b will be generated as Date type in DTO.

highsource commented 10 years ago

Yes, I clearly understood your use case. I just want to a pull request so that I could add adapter config to the schema for tests: https://github.com/highsource/jaxb2-basics/pulls

Pull request allows me to get directly to fixing the problem. If I first have to figure out the adapter configuration myself, it takes time and slows down the fix a bit.

Please see this article:

https://help.github.com/articles/using-pull-requests/

In essense, a pull request is changes you want me to add to my repository. Like "here's an adapter configuration for you to consider". With Git/GitHub I can normally merge the pull request with one click. And start working on the fix immeidately.

On Wed, Oct 29, 2014 at 11:12 AM, yinan-liu notifications@github.com wrote:

I didn't get you. What we do to parse the dateTime to Date is in binding file like

/jaxb:globalBindings the DateAdapter class is import java.util.Date; import org.joda.time.DateTime; import org.joda.time.format.DateTimeFormatter; import org.joda.time.format.ISODateTimeFormat; /** * * - @author */ public class DateAdapter { private static final DateTimeFormatter s_parser = ISODateTimeFormat.dateTimeParser().withZoneUTC(); private static final DateTimeFormatter s_formatter = ISODateTimeFormat.dateTime().withZoneUTC(); public static Date parseDateTime(String v) { try { return s_parser.parseDateTime(v).toDate(); } catch (Exception e) { return null; } } /*\* {@inheritDoc} */ public static String printDateTime(Date v) { return new DateTime(v).toString(s_formatter); } — Reply to this email directly or view it on GitHub https://github.com/highsource/jaxb2-basics/issues/3#issuecomment-60899301 .
yinan-liu commented 10 years ago

ok, got it, i will do that and let you know

yinan-liu commented 10 years ago

i did a pull request on my own branch yinan-liu:master, i suppose the merge to your master branch must be done on your side. i commit the config in the binding file and add a new java class DateAdapter used in the binding file, i did not change the maven dependency, so there must be compiling issue in this class. Let me know if it is ok for you.

highsource commented 10 years ago

You are awesome. :) Thank you.

On Wed, Oct 29, 2014 at 3:01 PM, yinan-liu notifications@github.com wrote:

i did a pull request on my own branch yinan-liu:master, i suppose the merge to your master branch must be done on your side. i commit the config in the binding file and add a new java class DateAdapter used in the binding file, i did not change the maven dependency, so there must be compiling issue in this class. Let me know if it is ok for you.

— Reply to this email directly or view it on GitHub https://github.com/highsource/jaxb2-basics/issues/3#issuecomment-60928010 .

yinan-liu commented 10 years ago

:-), thanks to you.

highsource commented 10 years ago

Here's a new issue:

https://github.com/highsource/jaxb2-basics/issues/9

Small hint: you can use xjc:javaType for a better adapter customization:

        <xjc:javaType name="java.util.Date" xmlType="xs:dateTime"
            adapter="org.jvnet.jaxb2_commons.plugin.simplify.tests01.DateAdapter" />

(Instead of specifying print and parse methods.)

highsource commented 10 years ago

@yinan-liu I think I have fixed in #9. Please see this comment:

https://github.com/highsource/jaxb2-basics/issues/9#issuecomment-60970483

Thank you very much for your contribution!

yinan-liu commented 10 years ago

I tried the solution, but i can not have the Date as the type. You can not reproduce the issue, can you?

yinan-liu commented 10 years ago

do I need to checkout the latest code ?

yinan-liu commented 10 years ago

tried with latest plugin code, it doesn't change anything, the element applied the plugin has the String as type, not Date

highsource commented 10 years ago

Let's continue in #9.

highsource commented 10 years ago

@yinan-liu https://github.com/highsource/jaxb2-basics/issues/9#issuecomment-61077171