Programmatically use WsImport with JAXB plugins without Maven or ANT?
Asked Answered
E

2

12

I am using WsImport to generate some Java sources from a remote WSDL file. Note that this is being from inside a regular Scala project i.e. it is not being done in a Maven or Ant build:

import com.sun.tools.ws.WsImport

def run(wsdlFile: File, destination: File, packageName: String = "generated"): Seq[File] = {        
  sys.props("javax.xml.accessExternalDTD") = "all"
  sys.props("javax.xml.accessExternalSchema") = "all"
  val xjcArgs = "" //TODO
  val args = s"-Xnocompile -XadditionalHeaders $xjcArgs -J-Djavax.xml.accessExternalDTD=all -b http://www.w3.org/2001/XMLSchema.xsd -p $packageName -s $destination $wsdlFile"
  WsImport.doMain(args.split(' '))
}

The above code works great and I use it to generate a Java WSDL client programatically from above Scala code.

But, now, I also want to use some WsImport plugins (such as this and this):

val xjcArgs = "-B-Xequals -B-XhashCode -B-Xvalue-constructor"

I am getting this error: no such JAXB option: -Xequals even though I added the following to my classpath:

"org.jvnet.jaxb2_commons" % "jaxb2-basics" % "1.11.1",
"org.jvnet.jaxb2_commons" % "jaxb2-value-constructor" % "3.0",

How do I force WsImport to use these plugins? Or do I use some other tool besides the WsImport (such as ANT) directly?

Trying with ANT

I am using com.sun.tools.ws.WsImport above but there is also another com.sun.tools.ws.ant.WsImport and I am not compeltely sure how to use it. I tried this:

val task = new com.sun.tools.ws.ant.WsImport2()
task.setPackage(packageName)
task.setWsdl(wsdlFile.getAbsolutePath)
task.setDestdir(destination.getAbsoluteFile)
task.setGenerateJWS(true)
task.setXadditionalHeaders(true)
task.setXnocompile(true)
task.setBinding("http://www.w3.org/2001/XMLSchema.xsd")
task.execute()

The above "almost works" but I can't figure out how to set binding in the ant task. wsimport takes in a -b http://www.w3.org/2001/XMLSchema.xsd but the ant task only accepts files as arguments :(

Ebenezer answered 3/10, 2017 at 18:5 Comment(0)
S
3

Can you modify your val xjcArgs to include classpath there. e.g

val xjcArgs = "-cp _path_ofjaxb2-basics.jar:other_plugin_jar_with_path -B-Xequals -B-XhashCode -B-Xvalue-constructor" to make sure classpath is set on WSImport call?

Edit

Based on comment: here is my ant command that does. Basically you need all the supporting jars as well.

<project name="jaxws-stack" default="wsimport">
<property name="jaxws.home" location="D:/tmp/wsimport"/>
<path id="wsimport.classpath">
    <fileset dir="${basedir}/lib">
            <include name="*.jar"/>
        </fileset>
</path>

<taskdef name="wsimport" classname="com.sun.tools.ws.ant.WsImport" classpathref="wsimport.classpath"/>

<target name="wsimport">
    <wsimport keep="true" verbose="true" wsdl="mywsdlurl_path">
        <xjcarg value="-Xequals"/>
        <xjcarg value="-XhashCode"/>
        <xjcarg value="-Xvalue-constructor"/>
    </wsimport>
</target>

In my D:/tmp.wsimport I have following jars:

       233,859 commons-beanutils-1.9.2.jar
       315,805 commons-lang3-3.1.jar
       293,543 commons-lang3-3.1.jar.zip
        60,686 commons-logging-1.1.1.jar
        23,205 istack-commons-runtime-2.21.jar
         7,595 istack-commons-tools-1.1.jar
        25,446 istack-commons-tools-2.21.jar
       866,992 jaxb-impl-2.1.10.jar
     3,147,690 jaxb-xjc-2.1.11.jar
       141,087 jaxb2-basics-1.11.1.jar
       166,736 jaxb2-basics-runtime-1.11.1.jar
       141,604 jaxb2-basics-tools-1.11.1.jar
         5,756 jaxb2-value-constructor-3.0.jar
     1,284,131 jaxws-rt-2.1.4.jar
       510,892 jaxws-tools-2.1.4.jar
        33,739 stax-ex-1.7.7.jar
       130,161 streambuffer-0.9.jar

Just call Ant's default target and you will get proper java files.

Edit 2 to support command line/programmatic call.

.

Option 1:

Call just the WSImport.

"jdk_location\bin\java.exe"    -cp "lib\*" com.sun.tools.ws.WsImport -keep -verbose -B-Xequals -B-XhashCode -B-Xvalue-constructor  http://www.webservicex.com/globalweather.asmx?WSDL

Option 2

Call via custom class.

Java class:

package test;

import com.sun.tools.ws.WsImport;

public class Test
{
    public static void main(String args []) throws Throwable
    {
        WsImport.doMain(args); 
    }
}

Command prompt call

"jdk_location\bin\java.exe" -cp ".;lib\*" test.Test  -keep -verbose -B-Xequals -B-XhashCode -B-Xvalue-constructo
r  -Xnocompile http://www.webservicex.com/globalweather.asmx?WSDL

Option 2c

Again a custom java class/method which you can use in scala to use. Make sure you have the classpath properly set with the jars I listed.

package test;

import com.sun.tools.ws.WsImport;
public class MyWSImport {

    public static void main(String[] args) throws Throwable {

        String [] input = new String[] {"-keep",
                                "-verbose","-B-Xequals",
                                "-B-XhashCode",
                                "-B-Xvalue-constructor","-Xnocompile",
                                "http://www.webservicex.com/globalweather.asmx?WSDL"};
        WsImport.doMain(input); 

    }

    public void execute() throws Throwable
    {

        String [] input = new String[] {"-keep",
                                "-verbose","-B-Xequals",
                                "-B-XhashCode",
                                "-B-Xvalue-constructor","-Xnocompile",
                                "http://www.webservicex.com/globalweather.asmx?WSDL"};
        WsImport.doMain(input); 
    }
}
Substage answered 9/10, 2017 at 11:45 Comment(14)
Maybe I did not understand what you meant by "make sure classpath is set on WSImport call". I got same error with your approach. Is your idea same as running this: wsimport -cp ~/.ivy2/cache/org.jvnet.jaxb2_commons/jaxb2-basics/jars/jaxb2-basics-1.11.1.jar -B-Xequals -B-XhashCode -B-XtoString -B-Xcopyable -B-Xsetters -B-Xvalue-constructor -Xnocompile -XadditionalHeaders -J-Djavax.xml.accessExternalDTD=all -b http://www.w3.org/2001/XMLSchema.xsd -p com.company.foo.wsdl -s generated_sources /path/to/file.wsdl?? I get same error from command line OR scala ...Ebenezer
Also note that I am using com.sun.tools.ws.WsImport but there is also another com.sun.tools.ws.ant.WsImport but I am not sure how to invoke that one..Ebenezer
Yes, that is a good idea to compare the command outside scala and then try inside scalaSubstage
This talks of a number of jars and not just jaxb2-basic-1.11.1.jar. confluence.highsource.org/display/J2B/JAXB2+Basics+Plugins You can try their ant file first to validateSubstage
I tried with -cp lib/jaxb2-basics/jars/jaxb2-basics-1.11.1.jar:lib/jaxb2-basics-runtime/jars/jaxb2-basics-runtime-1.11.1.jar:lib/jaxb2-basics-tools/jars/jaxb2-basics-tools-1.11.1.jar - still the same error: no such JAXB option: -XhashCodeEbenezer
let me try tomorrow again.Substage
@Ebenezer Yes I am able to achieve this. Updating the answer in a bitSubstage
Wait my question specifically said that I am not using ANT! Even if I did use ANT, I have to invoke it programatically through com.sun.tools.ws.ant.WsImport. Can you tell me how did you programatically invoke this from Java??Ebenezer
I know, that part, but later in comments you said you wanted just command like to work. And ant can be very well converted to work in command line. It's not too difficult to refactor it using java call/cmd line call. Updating answer with all three options @Ebenezer Probably for final timeSubstage
Updated final answer from me. @Ebenezer If that can't help, I will take your excuse. thanksSubstage
I never said I wanted just command line to work - I was responding to you saying that it was good idea to compare from outside and inside and first getting command line to work would be a good step to eventually getting it working from inside Java..Ebenezer
The last example has java thing. Just call the java method MyWsImport.execute() with proper classpath and you shall be fine @pathikrit. If there is any class missing, it will give you even a better ClassNotFoundException and hence will be more usefulSubstage
Thanks @Substage - I will give it a try. As I said, I am invoking this not from command line but from pure Scala (same as pure Java) code. I don't understand what do you mean by Make sure you have the classpath properly set. How did you set it??? Did you run this yourself and it worked for you??Ebenezer
I would not have posted without trying. You call just as you call a java function. From your main class, or whatever class your application is running, just call new MyWSImport().execute() or you can even make the function static and call it directly MyWSImport.execute.Substage
P
1

I am at the same deadlock as the author of the thread trying to tweak gradle's Java source code generation from wsdl.

And the reason for that is jaxb2-basics implements com.sun.tools.xjc.Plugin and @Optional in his answer refers to com.sun.tools.ws.WsImport. At the same time wsimport utility of "modern" Jdk8 rather implements com.sun.tools.internal.ws.WsImport and use com.sun.tools.internal.xjc.Plugin. So jaxb2-basics become kind of obsolete for using with wsimport of Jdk8.

The solution would be to use alternative library to provide WsImport in "old" namespace. E.g. com.sun.xml.ws:jaxws-tools:2.3.0. In Gradle it looks like:

configurations {
  jaxws
}

dependencies {
  jaxws 'org.jvnet.jaxb2_commons:jaxb2-basics:0.11.1'
  jaxws 'com.sun.xml.ws:jaxws-tools:2.3.0'

  compile 'org.jvnet.jaxb2_commons:jaxb2-basics-runtime:0.11.1'
}

wsdlServices.each { u ->
  task "ws${u.service}" (type: JavaExec) {
    classpath = configurations.jaxws

    workingDir = generatedDir
    main = 'com.sun.tools.ws.WsImport'
    args = ['-keep', '-Xnocompile', '-B-XtoString', '-B-Xequals', '-B-XhashCode', u.url]

    compileJava.dependsOn path // depends on current task
  }
}

and in command line this will be:

java -cp "lib/*" com.sun.tools.ws.WsImport -extension -keep -Xnocompile -B-XtoString 'http://www.webservicex.com/globalweather.asmx?WSDL'

where lib contains

commons-beanutils-1.9.2.jar
commons-collections-3.2.1.jar
commons-lang3-3.2.1.jar
FastInfoset-1.2.13.jar
gmbal-api-only-3.1.0-b001.jar
ha-api-3.1.9.jar
javaparser-1.0.11.jar
javax.annotation-api-1.3.jar
javax.xml.soap-api-1.4.0.jar
jaxb2-basics-0.11.1.jar
jaxb2-basics-runtime-0.11.1.jar
jaxb2-basics-tools-0.11.1.jar
jaxb-api-2.3.0.jar
jaxb-core-2.3.0.jar
jaxb-impl-2.3.0.jar
jaxb-jxc-2.3.0.jar
jaxb-xjc-2.3.0.jar
jaxws-api-2.3.0.jar
jaxws-rt-2.3.0.jar
jaxws-tools-2.3.0.jar
jcl-over-slf4j-1.7.7.jar
jsr181-api-1.0-MR1.jar
management-api-3.0.0-b012.jar
mimepull-1.9.7.jar
policy-2.7.2.jar
resolver-20050927.jar
saaj-impl-1.4.0.jar
slf4j-api-1.7.7.jar
stax-ex-1.7.8.jar
streambuffer-1.5.4.jar

i.e. org.jvnet.jaxb2_commons:jaxb2-basics:0.11.1 and com.sun.xml.ws:jaxws-tools:2.3.0 with dependencies

Patrizio answered 7/3, 2018 at 12:33 Comment(1)
JAXB2-Basics is not "obsolete", it is simply incompatible with "internal" JAXB. Please see: #50670067Cauvery

© 2022 - 2024 — McMap. All rights reserved.