Is there any way to make default WSDL being generated by JAX-WS (returned via ?wsdl) to use XML choice instead of any and sequence?
I assume you mean the XML schema in the <types/> part of the WSDL. The generation of this schema is not governed by JAX-WS, but by the JAXB specification. This is the specification for the data binding in JAX-WS.
But to actually answer your question: Yes, you can do that with an appropriate #XMLElements annotation in the class that represents your datatype. For example, take a web service interface like this:
#WebService
public interface Chooser {
String chooseOne(Choice myChoice);
}
Then the contents of your XSD depend on the structure of the Choice class. You can force the generation of a choice element through something like this:
public class Choice {
#XmlElements(value = { #XmlElement(type = First.class),
#XmlElement(type = Second.class) })
private Object myChoice;
}
Classes First and Second are possible elements in the choice. The schema generated from this code looks like this:
<xs:complexType name="choice">
<xs:sequence>
<xs:choice minOccurs="0">
<xs:element name="myChoice" type="tns:first"></xs:element>
<xs:element name="myChoice" type="tns:second"></xs:element>
</xs:choice>
</xs:sequence>
</xs:complexType>
This still wraps the choice in a sequence, but as there is only one element in the sequence, this doesn't really matter.
Related
we are trying to add parameters to a transformation at the runtime. The only possible way to do so, is to set every single parameter and not a node. We don't know yet how to create a node for the setParameter.
Current setParameter:
QName TEST XdmAtomicValue 24
Expected setParameter:
<TempNode> <local>Value1</local> </TempNode>
We searched and tried to create a XdmNode and XdmItem.
If you want to create an XdmNode by parsing XML, the best way to do it is:
DocumentBuilder db = processor.newDocumentBuilder();
XdmNode node = db.build(new StreamSource(
new StringReader("<doc><elem/></doc>")));
You could also pass a string containing lexical XML as the parameter value, and then convert it to a tree by calling the XPath parse-xml() function.
If you want to construct the XdmNode programmatically, there are a number of options:
DocumentBuilder.newBuildingStreamWriter() gives you an instance of BuildingStreamWriter which extends XmlStreamWriter, and you can create the document by writing events to it using methods such as writeStartElement, writeCharacters, writeEndElement; at the end call getDocumentNode() on the BuildingStreamWriter, which gives you an XdmNode. This has the advantage that XmlStreamWriter is a standard API, though it's not actually a very nice one, because the documentation isn't very good and as a result implementations vary in their behaviour.
Another event-based API is Saxon's Push class; this differs from most push-based event APIs in that rather than having a flat sequence of methods like:
builder.startElement('x');
builder.characters('abc');
builder.endElement();
you have a nested sequence:
Element x = Document.elem('x');
x.text('abc');
x.close();
As mentioned by Martin, there is the "sapling" API: Saplings.doc().withChild(elem(...).withChild(elem(...)) etc. This API is rather radically different from anything you might be familiar with (though it's influenced by the LINQ API for tree construction on .NET) but once you've got used to it, it reads very well. The Sapling API constructs a very light-weight tree in memory (hance the name), and converts it to a fully-fledged XDM tree with a final call of SaplingDocument.toXdmNode().
If you're familiar with DOM, JDOM2, or XOM, you can construct a tree using any of those libraries and then convert it for use by Saxon. That's a bit convoluted and only really intended for applications that are already using a third-party tree model heavily (or for users who love these APIs and prefer them to anything else).
In the Saxon Java s9api, you can construct temporary trees as SaplingNode/SaplingElement/SaplingDocument, see https://www.saxonica.com/html/documentation12/javadoc/net/sf/saxon/sapling/SaplingDocument.html and https://www.saxonica.com/html/documentation12/javadoc/net/sf/saxon/sapling/SaplingElement.html.
To give you a simple example constructing from a Map, as you seem to want to do:
Processor processor = new Processor();
Map<String, String> xsltParameters = new HashMap<>();
xsltParameters.put("foo", "value 1");
xsltParameters.put("bar", "value 2");
SaplingElement saplingElement = new SaplingElement("Test");
for (Map.Entry<String, String> param : xsltParameters.entrySet())
{
saplingElement = saplingElement.withChild(new SaplingElement(param.getKey()).withText(param.getValue()));
}
XdmNode paramNode = saplingElement.toXdmNode(processor);
System.out.println(paramNode);
outputs e.g. <Test><bar>value 2</bar><foo>value 1</foo></Test>.
So the key is to understand that withChild() returns a new SaplingElement.
The code can be compacted using streams e.g.
XdmNode paramNode2 = Saplings.elem("root").withChild(
xsltParameters
.entrySet()
.stream()
.map(p -> Saplings.elem(p.getKey()).withText(p.getValue()))
.collect(Collectors.toList())
.toArray(SaplingElement[]::new))
.toXdmNode(processor);
System.out.println(paramNode2);
I have a question concerning an Error I experience while trying to read an XML-File through the XNA 4.0 Content Pipeline in order to build Objects. First I reused old XNA 3.1 Code of mine which worked back in the day but now throws the an Error Message:
Building content threw InvalidOperationException: Instanzen von abstrakten Klassen können nicht erstellt werden. (Unable to build Instances of abstract Classes - roughly translated)
at ReflectionEmitUtils()
...and goes on forever, I can post it, if it's needed, but for better readability of my initial request..
Then I used this Method but it throws the same error.
These are the relevant pieces of source code:
I've written a class to define the content/structure of the XML-File:
public class Command
{
public List<bool> mButtons;
public List<Keys> keys;
public Enum iD;
}
And this is my XML File, with which I want to build Command-Objects
<?xml version="1.0" encoding="utf-8" ?>
<XnaContent>
<Asset Type="KinectRTS_Input.Command">
<mButtons>true/mButtons>
<keys>
<Item>LeftControl/Item>
</keys>
<iD>SMulti/iD>
</Asset>
</XnaContent>
(In my code, the Brackets are all correct, though since this Form processes XML-Tags...;))
I used a Test-Application in order to find out, which Format the XNA-Serializer uses to output List-Items and enums, so I'm reasonably sure, that there's not the error.
It looks like either your XML is invalid or your Model is. For the mButtons field, you have defined it as a List<bool> but in the XML it's a bool not a List<bool>. I would either edit the XML to have the <mButtons> element contain a single <Item> element or change the declaration of mButtons in the Model to be a bool not List<bool>.
Too easy...the problem wasn't with the Lists, in fact the Test-Application mentioned in my request actually returned XML-Tags with Item-Tags for the keys-List and without Item-Tags for the bool-list. Wrapping the bool into Item-Tags resulted in an " at not expected"-Error. I have no idea, why the Serializer handles List and List differently, though.
The problem was the Enum 'iD', which is an abstract class and thus throws the Error mentiones above. It seems that I was overwhelmed by the sheer size of the error-message and just disregarded the crucial bit of info - that the Serializer tries to build an abstract class.
But thanks anyway. – Kuroni Kaimei
I'm a grails newbie working on a project for fun. I'm serializing a class like this:
def msg = (listing as XML).toString()
the trying to deserialize a class using the XMLSlurper like this:
def root = new XmlSlurper().parseText(listingString)
def sellerNode = root.seller
I'm trying to reconstruct this object:
Listing{
Date dateCreated
String description
Date endDateTime
String name
Float startingPrice
Customer winner
static hasMany = [bids: Bid] // B-4
static belongsTo = [seller: Customer]
}
}
from this xml:
<?xml version="1.0" encoding="UTF-8"?>
<listing>
<bids>
<bid>
<amount>10.5</amount>
<bidder>
<accountExpired>false</accountExpired>
<accountLocked>false</accountLocked>
<dateCreated/>
<emailAddress>validguy#valid.com</emailAddress>
<enabled>false</enabled>
<password>secret</password>
<passwordExpired>false</passwordExpired>
<username>validguy</username>
</bidder>
<dateCreated>2012-04-08 21:16:41.423 CDT</dateCreated>
<listing/>
</bid>
<bid>
<amount>10.0</amount>
<bidder>
<accountExpired>false</accountExpired>
<accountLocked>false</accountLocked>
<dateCreated/>
<emailAddress>validguy#valid.com</emailAddress>
<enabled>false</enabled>
<password>secret</password>
<passwordExpired>false</passwordExpired>
<username>validguy</username>
</bidder>
<dateCreated>2012-04-08 21:16:41.415 CDT</dateCreated>
<listing/>
</bid>
</bids>
<dateCreated/>
<description>A test listing</description>
<endDateTime>2012-04-09 21:16:41.407 CDT</endDateTime>
<name>Default</name>
<seller>
<accountExpired>false</accountExpired>
<accountLocked>false</accountLocked>
<dateCreated/>
<emailAddress>validguy#valid.com</emailAddress>
<enabled>false</enabled>
<password>secret</password>
<passwordExpired>false</passwordExpired>
<username>validguy</username>
</seller>
<startingPrice>10.0</startingPrice>
<wasNotificationSent>false</wasNotificationSent>
<winner>
<accountExpired>false</accountExpired>
<accountLocked>false</accountLocked>
<dateCreated/>
<emailAddress>validguy#valid.com</emailAddress>
<enabled>false</enabled>
<password>secret</password>
<passwordExpired>false</passwordExpired>
<username>validguy</username>
</winner>
</listing>
First I'm having issues getting to the values of each node. I've tried def seller = new Customer(name:sellerNode.#username) but that doesn't work since I assume #username needs to be an attribute and not an element.
Second, do I have to parse this xml "by hand"? Isn't there a better way to deserialize this xml automatically?
I already looked at a couple of posts and including this one: Import XML into a Grails Domain Class however as you can see, my xml doesn't have attributes like the xml in this post.
Thanks,
If the source of the XML is a web request, you can add parseRequest: true to the UrlMapping for your controller, grails will parse the XML request automatically. The XML will be presented as params and you can do data binding the same as any other request.
If you're getting the XML from another source, take a look at the XML to parameter map conversion in the class XMLParsingParameterCreationListener.groovy.
I did look at the class aTaylor suggested but due to time constraints I ended up parsing the xml with the slurper this way:
def listing = new XmlSlurper().parseText(listingXML)
def winner = listing."winner"."username".text()
I was constrained by the fact that I can only get at text values. For instance, I couldn't deserialize the bids elements into a collection and perform calculations like bids.Max(b->b.amount). That was my ultimate goal.
BTW - This is was not a web request. It was a MQ message serialized as xml.
I have a requirement to send an object as xml to a webservice. I already have the pojo, now I need to convert it to xml using Groovy. In grails I have used the as keyword, what is the equivalent code to do this in Groovy?
Example Grails code:
import grails.converters.*
render Airport.findByIata(params.iata) as XML
A naive example of doing this with StreamingMarkupBuilder would be:
class Airport {
String name
String code
int id
}
Writable pogoToXml( object ) {
new groovy.xml.StreamingMarkupBuilder().bind {
"${object.getClass().name}" {
object.getClass().declaredFields.grep { !it.synthetic }.name.each { n ->
"$n"( object."$n" )
}
}
}
}
println pogoToXml( new Airport( name:'Manchester', code:'MAN', id:1 ) )
Which should print:
<Airport><name>Manchester</name><code>MAN</code><id>1</id></Airport>
The as keyword is actually part of the Groovy language spec. The part you are missing is the XML class that does the conversion. This is really just a fancy class that walks the POJO and writes the XML (possibly using MarkupBuilder).
Groovy does not have a built-in class like grails.converters.XML that makes it so easy. Instead, you'll need to manually build the XML using MarkupBuilder or StreamingMarkupBuilder.
Neither of these will automatically convert a POJO or POGO to XML, you'll have to either process this yourself manually, or use reflection to automate the process.
I'd suggest that you might be able to copy the grails converter over, but it may have a lot of dependencies. Still, it's open source, that might be a starting point if you need a more reusable component.
When I access a JPA managed date value from JSF, it comes back with an javax.faces.component.UdateModelException saying
'Cannot convert 01.01.10 00:00 of type class java.util.Date to class org.apache.openjpa.util.java$util$Date$proxy
Using a JPA-managed date value (which means it is proxied) works fine when it is used directly from the EL likes this:
'<h:outputLabel value="MyDateValue" for="input"/>
'<h:inputText id="inputDate" value="#{bean.myDate}"/>
However, it causes trouble when trying to use it with composite components
and gives back the following converter exception and thus can't update the model...
The (simplified) JSF composite component inputDate.xhtml
<head>
<title>A date input field</title>
</head>
<composite:interface>
<composite:attribute name="dateValue"/>
</composite:interface>
<composite:implementation>
<h:outputLabel value="MyDateValue" for="input"/>
<h:inputText id="input" value="#{cc.attrs.dateValue}"/>
</composite:implementation>
Assumption:
It seems the proxy replacement in OpenJPA is handled differently when the value is being accessed from inside a composite. My guess is the EL-resolver handles calls to object values differently when it is passed to composites. Passing it to composites means it is first accessed within the composite, which is too late and the required replacement of the proxy is not accomplished (thus the converter exception)
So I tried to change the Expression Language for MyFaces, but it didn't work in Websphere, even though I changed the class loading to parent last and provided el-impl and el-api from glassfish in the lib folder and inserted the necessary context-param for MyFaces
How do you guys use JPA-managed dates (or other proxied entities) in composite components???
If you are using the sun EL implementation you might use the following ELResolver which works around this issue:
public class BugfixELResolver extends ELResolver {
//...
#Override
public Class<?> getType(ELContext anElContext, Object aBase, Object aProperty) {
if (aBase.getClass().getCanonicalName().equals("com.sun.faces.el.CompositeComponentAttributesELResolver.ExpressionEvalMap")){
Object tempProperty=((Map)aBase).get(aProperty);
if (tempProperty!=null&&tempProperty.getClass().getCanonicalName().equals("org.apache.openjpa.util.java.util.Date.proxy")) {
anElContext.setPropertyResolved(true);
return java.util.Date.class;
}
}
return null;
}
}
Add it to the faces-config this way:
<el-resolver>
xxx.BugfixELResolver
</el-resolver>
This workaround can also be used in environments where you can not change the EL implementation (like websphere etc.).
Here is the workaround. The problem seems to be WebSpheres' ExpressionLanguage Implementation or rather the order resolvers are executed. Registering the JBoss EL implementation works and resolves the date proxies before calling the composite component. I also tried the Glassfish EL, but it didn't work either...
Registering a alternative EL is quite strange: The setting in web.xml for MyFaces is
<context-param>
<param-name>org.apache.myfaces.EXPRESSION_FACTORY</param-name>
<param-value>org.jboss.el.ExpressionFactoryImpl</param-value>
</context-param>
Additionally under WebContent/META-INF/services/ a file named javax.el.expressionFactory is needed with this single line org.jboss.el.ExpressionFactoryImpl. The class comes from jboss-el-2.0.2.CR1.jar
(sorry, couldn't find the link to a maven repo)
I will keep you updated once I find a better solution...