Closed zman0900 closed 5 years ago
Which error are you getting, exactly? Please also post a sample class.
Error is java.lang.NoSuchFieldError: INSTANCE
when calling the toString method of a generated JAXB class, where the error points to the first line of that generated toString method:
final ToStringStrategy2 strategy = JAXBToStringStrategy.INSTANCE;
Easiest way I have found to reproduce this is to create one maven project which generates any JAXB class(s) from a schema using the older 0.11.1 jaxb2-basics, including the -XtoString
arg. Exact setup I used was this:
<plugin>
<groupId>org.jvnet.jaxb2.maven2</groupId>
<artifactId>maven-jaxb2-plugin</artifactId>
<version>0.13.3</version>
<executions>
<execution>
<goals>
<goal>generate</goal>
</goals>
<configuration>
<schemaDirectory>${project.build.outputDirectory}</schemaDirectory>
<bindingDirectory>src/main/xjb</bindingDirectory>
<args>
<arg>-mark-generated</arg>
<arg>-XtoString</arg>
<arg>-XsimpleEquals</arg>
<arg>-XsimpleHashCode</arg>
<arg>-Xsetters</arg>
<arg>-Xsetters-mode=direct</arg>
<arg>-Xcopyable</arg>
<arg>-enableIntrospection</arg>
</args>
<plugins>
<plugin>
<groupId>org.jvnet.jaxb2_commons</groupId>
<artifactId>jaxb2-basics</artifactId>
<version>0.11.1</version>
</plugin>
</plugins>
</configuration>
</execution>
</executions>
</plugin>
Then, in a second separate project, include the jar produced from the first project as a dependency, along with jaxb2-basics-runtime 0.12.0. Then create a simple class like this:
public class Junk {
public static void main(String... args) {
// MyJaxbClass is any of the classes generated from your other project.
MyJaxbClass x = new MyJaxbClass();
// This will throw the NoSuchFieldError at runtime.
System.out.println(x.toString());
}
}
java.lang.NoSuchFieldError: INSTANCE
at org.mine.MyJaxbClass.toString(MyJaxbClass.java:nnn)
Could you please prepare a minimal reproducing project?
Am 11.06.2018 um 18:28 schrieb Dan Ziemba notifications@github.com:
Error is java.lang.NoSuchFieldError: INSTANCE when calling the toString method of a generated JAXB class, where the error points to the first line of that generated toString method:
final ToStringStrategy2 strategy = JAXBToStringStrategy.INSTANCE; Easiest way I have found to reproduce this is to create one maven project which generates any JAXB class(s) from a schema using the older 0.11.1 jaxb2-basics, including the -XtoString arg. Exact setup I used was this:
Then, in a second separate project, include the jar produced from the first project as a dependency, along with jaxb2-basics 0.12.0. Then create a simple class like this: public class Junk { public static void main(String... args) { // MyJaxbClass is any of the classes generated from your other project. MyJaxbClass x = new MyJaxbClass(); // This will throw the NoSuchFieldError at runtime. System.out.println(x.toString()); } } java.lang.NoSuchFieldError: INSTANCE at org.mine.MyJaxbClass.toString(MyJaxbClass.java:nnn) — You are receiving this because you commented. Reply to this email directly, view it on GitHub, or mute the thread. org.jvnet.jaxb2.maven2 maven-jaxb2-plugin 0.13.3 generate ${project.build.outputDirectory} src/main/xjb -mark-generated -XtoString -XsimpleEquals -XsimpleHashCode -Xsetters -Xsetters-mode=direct -Xcopyable -enableIntrospection org.jvnet.jaxb2_commons jaxb2-basics 0.11.1
I'll try to throw something together in the next few days. It appears this also applies to the copyable plugin.
I put together an example. This was tested with Java 8.
mvn install
for the common module so it is available in your local repo.mvn test
for the user module. Two of the tests should print the NoSuchFieldErrors from the toString and clone failures.java.lang.NoSuchFieldError: INSTANCE
at com.example.common.Item.toString(Item.java:108)
at zman0900.DemoTest.commonToStringFails(DemoTest.java:42)
java.lang.NoSuchFieldError: INSTANCE
at com.example.common.Item.copyTo(Item.java:140)
at com.example.common.Item.clone(Item.java:136)
at zman0900.DemoTest.commonCloneFails(DemoTest.java:61)
Thank you, I will take a look the next days.
I've checked the code.
I'm afraid there's not much I can do. Seems you can't combine pre-0.12.0 with post-0.12.0 code.
Seems you can't combine pre-0.12.0 with post-0.12.0 code.
Turns out this is not entirely true. I realized I have another dependency on a library that contains JAXB classes generated with a much older version of jaxb2-basics, 0.6.4, with toString enabled. That code actually runs fine under the 0.12.0 runtime.
For anyone else reading this, I have worked around the 0.11 vs 0.12 issue by just disabling the toString and copyable plugins in my library code, then I wrote my own very simple runtime-free toString plugin. This only works since I know none of the users of my library depend on clone/copyTo, and because my schemas are simple enough for my toString plugin (i.e. nothing like List<JAXBElement>
is generated).
Careful there.
What I've found out is that combining pre-0.12.0 (0.11.1) and 0.12.0 does not work for some reason I don't really quite understand. I get java.lang.NoSuchFieldError: INSTANCE
on access to INSTANCE
field of JAXBCopyStrategy
(and likes) where the INSTANCE
field does exist. I do not know how it can be so, I'll try to ask on StackOverflow. The problem appears when transitioning from 0.12.0-generated code to 0.11.1-generated code. The worst thing is that the problem appears in the runtime.
So unless we figure out what the problem is, it is basically a ticking bomb. From this point, there are only two safe approaches:
I think updating the code to 0.12.0 is absolutely the way to go. No matter how hard we try, there will definitely be breaking changes, from time to time. It is naive trying to stick with old APIs because of the "never touch the running system" sentiment. This will not work in the long run and I, sorry, will not be willing to provide support migrating 0.6.4 to 1.12.8 somewhen in the future.
As for not using runtime-dependent plugins, the primary focus of JAXB2 Basics will always be plugins which generate runtime-dependent code. There are many reasons for it:
JAXBCopyStrategy
, DefaultCopyStrategy
). Avoiding runtime means most of this code must be added to the generated code. Which blows the generated code, and makes changes to the strategy code to be quite hard. This alone on my book is a good price to pay for the runtime dependency.id
or typed UUID
". Or "compare these two structures and tell me where they are different". That's what's possible with strategies - and they need interfaces, ergo a runtime dependency.I did implement SimpleEquals
and SimpleHashCode
due to popular demand, but to be honest these are second-class products.
I also started SimpleToString
but did not get far with it. It is quite difficult to implement it correctly, with the consideration of JAXBElement
or DOM etc.
I'm closing this as WONTFIX
as I'm afraid there's not much I can do here.
I have a project that generates JAXB code and publishes a maven artifact to be shared by several other projects. While attempting to update one of those downstream projects, this version incompatibility was found.
The common project generates JAXB code from a schema using jaxb2 plugin 0.13.3 and jaxb2-basics 0.11.1, with the "-XtoString" arg enabled. In the downstream project, I have updated to jaxb2 plugin 0.14.0 and jaxb2-basics 0.12.0. This project generates additional JAXB code from another schema which imports the common schema. This is done by including the "episode" of the common project's maven artifact for the jaxb2 plugin.
This leads to an error at runtime since classes generated with the older code from the common module contain this in their toString methods:
while classes generated with the newer code contain:
In the 0.12.0 version of the runtime, the INSTANCE variable has type "ToStringStrategy" and INSTANCE2 has type "JAXBToStringStrategy", which implements "ToStringStrategy2". But in the 0.11.1 version, INSTANCE had type "JAXBToStringStrategy".
Can this be fixed, or will I be required to upgrade the version of all projects at once?