I use Hyperjaxb3 to generate JPA entities from XSD schema. I have a xsd:string type that I want to use for description text (text area in the UI):
<xsd:complexType name="Description">
<xsd:simpleContent>
<xsd:extension base="**xsd:string**">
<xsd:attribute name="abc" type="xsd:NCName" use="optional" />
</xsd:extension>
</xsd:simpleContent>
</xsd:complexType>
Hyperjaxb3 generates class (entity) Description with attribute value, annotated like this:
#Basic
#Column(name = "VALUE_", **length = 255**)
public String getValue() {
return value;
}
The questions I have:
I saw that if I put xsd:maxLength restriction on xsd:simpleType, JPA #Column.length has the value of maxLength. How can I set xsd:rescriction on xsd:simpleContent that is xsd:extension of xsd:string? Do I have to define a complexType with xsd:resctriction that I will extend? And if yes, will Hyperjaxb generate #Column.length by my restriction. I tried following:
<xsd:simpleType name="DescriptionParent">
<xsd:restriction base="xsd:string">
<xsd:maxLength value="4096" />
</xsd:restriction>
</xsd:simpleType>
<xsd:complexType name="Description">
<xsd:simpleContent>
<xsd:extension base="DescriptionParent">
<xsd:attribute name="abc" type="xsd:NCName" use="optional" />
</xsd:extension>
</xsd:simpleContent>
</xsd:complexType>
But the JPA column length is still 255.
Is it also possible to set in my JAXB customization (*.xjb file) the lenght of the column for given type (somehow let hyperjaxb know that this is the orm I want to use for my specific type)? Or is it totally out of the way and xsd:maxLength should be used (above) I managed to set it globally for Hyperjaxb customization:
Thanks for your help.
Second question: yes, you can configure global type mappings for simple types.
See Per-type customization for single properties.
First question: it seems to be a bug/missing feature, please file an issue here.
Related
I am trying to generate a bunch of xml annotated pojos. To do this I have all my xsd files in the resource folder of my project (they are from the polycom rmx sdk, RmxSdkApiV7_8-EMA_EMA-V7_8_0_303). I then right click on each one (over 150 of them) go to generate and click JAXB classes. I pick the project and give it a namespace than finish the wizard. After doing this there is a warning that any newly generated classes will override existing ones. This is my problem, because some commonly used objects will have different definitions in different xsd files. So when the override happens whatever was defined is lost.
So for example, response_trans_conf.xsd defines GET as
<xsd:element name="GET">
<xsd:complexType>
<xsd:sequence>
<xsd:element ref="CONFERENCE" minOccurs="0"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
Where as another schema file like trans_conf_2.xsd defines GET as
<xsd:element name="GET">
<xsd:complexType>
<xsd:sequence>
<xsd:element ref="ID"/>
<xsd:element ref="OBJ_TOKEN"/>
<xsd:any processContents="skip" minOccurs="0" maxOccurs="unbounded" namespace="##other"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
So I'll end up with a Get object that looks like
public class GET {
#XmlElement(name = "CONFERENCE")
protected ConferenceContent conference;
OR (respectively)
public class GET {
#XmlElement(name = "ID", required = true)
protected BigInteger id;
#XmlElement(name = "OBJ_TOKEN", required = true)
protected String objtoken;
#XmlAnyElement
protected List<Element> any;
What I need is an object that a combination of both. Like I said there are over 150 xsd files in this sdk. So this problem is multiplied by few other common objects.
FYI at the same time of wanting a combined class rather then an overridden one Im hoping the solution would also prevent duplicates some how.
due to lack of answers I have implemented a workaround which is to manually add the missing/needed members.
Im sure the comment above by ulab would work as well but I really do not want to edit the xsd's
The other option I see but did not implement is a wrapper. extending these common classes to have all the members in another layer above the sdk's generated file. that would ensure the sdk doesnt need to be touch even when there is a new version and a new generation of files.
I have a custom stored procedure with in parameters that return fields of different tables how I can map this custom stored to an entity? I only want to use like a read only values for a report I don't want to save or something like that I try to add the extra fields to the most similar entity but when I execute the method in code the extra fields are null
Solution 1: Using a view
A view allows to aggregate data from different entities.
<Article>
<Id />
<Name />
<Lines typeName="LineCollection" />
<cf:method name="LoadArticlesByCommand" body="load(string commandName) from ArticleByCommand where CommandName = #commandName" />
<cf:view name="ArticleByCommand" autoLightweight="true">
<ArticleName expression="Name"/>
<ArticleQty expression="Lines.Quantity" />
<CommandName expression="Lines.Command.Name" />
</cf:view>
</Article>
<Command>
<Id />
<Name />
<Lines typeName="LineCollection" />
</Command>
<Line setType="List">
<Article typeName="Article" key="true" />
<Command typeName="Command" key="true" />
<Quantity typeName="int" />
</Line>
http://blog.codefluententities.com/2014/04/22/views-auto-lightweight-and-the-modeler/
https://www.softfluent.com/documentation/Views_PersistentViews.html
Solution 2: Using a lightweight entity
Instead of creating a view, you can can create a lightweight entity that contains only the properties used by the stored procedure.
<cf:entity name="Person" lightweight="true">
<cf:property name="FirstName" typeName="string" />
<cf:property name="lastName" typeName="string" />
<cf:method name="ComputeBalance"
body="load () raw"
rawBody="SELECT 'John' AS FirstName, 'Doe' AS LastName" />
</cf:entity>
Solution 3: Custom mapping
For more specific values or types, a custom method can be provided to map the database values to .NET types. This custom method will be called with a DataReader as parameter, meaning that a developer could do whatever he wants.
<cf:entity name="Sample">
<cf:method name="LoadPair" body="raw" rawBody="SELECT 1234,5678"
returnTypeName="CodeFluent.Runtime.Utilities.Pair<System.Int32,System.Int32>"
cfom:methodName="On{0}" />
<cf:snippet>
private static CodeFluent.Runtime.Utilities.Pair<int,int> OnLoadPair(System.Data.IDataReader reader)
{
return new Pair<int, int>(reader.GetInt32(0), reader.GetInt32(1));
}
</cf:snippet>
</cf:entity>
You can also use OnAfterReadRecord or OnBeforeReadRecord rules
If it is not essential that you map the results of the custom stored procedure to an entity than another option is to use the built in support for DataSets.
http://blog.codefluententities.com/2011/06/22/dataset-support-in-codefluent-entities/
<cf:method name="LoadAllCities" body="raw" returnTypeName="System.Data.DataSet">
SELECT $Address::City$ FROM $Address$
</cf:method>
.
DataSet ds = Address.LoadAllCities();
foreach (DataTable table in ds.Tables)
{
foreach (DataRow row in table.Rows)
{
Console.WriteLine("City: " + row[0]);
}
}
Upon re-reading you're question I am providing another answer.
In response to the part where you said "I try to add the extra fields to the most similar entity but when I execute the method in code the extra fields are null". The following steps should be able to solve that problem.
Execute one of the automatically created stored procedure in SQL Management Studio.
Execute the stored procedure you manually created.
Verify that the fieldnames returned by both stored procedures match.
I think the above will solve your immediate problem but I still don't like the solution. The reason is that you said you picked the most similar entity. I think that is going to cause problems in the future especially if the stored procedure is not being mapped to all of the entities properties.
I would recommend either lightweight entity, view or DataSet.
Is it possible to extract an attribute (as in XML attribute value) from a RequestWrapper object?
In my implementation, I'd like to use the value of the attribute, but can't reference it with #WebParam, as that is only for elements (I believe)
#SOAPBinding is defined "Document/Literal/Wrapped"
WSDL (relevant sections, target attribute at **):
<s:element name="GetStatus">
<s:complexType>
<s:element minOccurs="0" maxOccurs="1" name="Entity" type="s0:Entity"/>
**<s:attribute name="Handle" type="s:string"/>
</s:complexType>
</s:element>
<s:element name="GetStatusResponse">
<s:complexType>
<s:sequence>
<s:element minOccurs="0" maxOccurs="1" name="StatusCode" type="s0:StatusCode"/>
<s:element minOccurs="0" maxOccurs="1" name="Server" type="s0:Server"/>
</s:sequence>
</s:complexType>
</s:element>
<message name="GetStatusIn">
<part name="parameters" element="s0:GetStatus"/>
</message>
<message name="GetStatusOut">
<part name="parameters" element="s0:GetStatusResponse"/>
</message>
<portType name="Service">
<operation name="GetStatus">
<input message="s0:GetStatusIn"/>
<output message="s0:GetStatusOut"/>
</operation>
</portType>
SEI abstract method (able to specify XML elements with WebParam):
#WebMethod(operationName="GetStatus")
#RequestWrapper(localName=“GetStatus",className="com.example.GetStatus")
#ResponseWrapper(localName=“GetStatusResponse",className="com.example.GetStatusResponse")
public void getStatus(
#WebParam(name="Entity”)Entity entity,
#WebParam(name="StatusCode",mode=WebParam.Mode.OUT)Holder<StatusCode> statusCode,
#WebParam(name="Server", mode=WebParam.Mode.OUT)Holder<Server> server
);
Implementation:
#Override
public void getStatus(
Entity entity,
Holder<StatusCode> statusCode,
Holder<Server> server
) { ... }
It’s obvious how I can read the value of the #RequestWrapper bean Status (Entity via #WebParam), but is there any way to access the value (Handle) within Status. WebParam, as far as I understand, does not support attributes, only elements.
An alternate way to ask/seek solution might be asking how to access the full bean being referenced by RequestWrapper, in this case GetStatus.
I know if I transition to Document/Literal/Bare I can simply have the parameters and return value reflect the bean, but I'd prefer to solve this using wrapped as all information points to this being the most widely preferred binding.
Self-answered for posterity.
No. To qualify as wrapped style, only elements must be present.
Was reviewing the JAX-WS specification overnight
2.3.1.2 Wrapper Style
A WSDL operation qualifies for wrapper style mapping only if the following criteria are met:
(i) The operation’s input and output messages (if present) each contain only a single part
(ii) The input message part refers to a global element declaration whose localname is equal to the operation name
(iii) The output message (if present) part refers to a global element declaration
(iv) The elements referred to by the input and output message (if present) parts (henceforth referred to as
wrapper elements) are both complex types defined using the xsd:sequence compositor
(v) The wrapper elements only contain child elements, they MUST not contain other structures such
as wildcards (element or attribute), xsd:choice, substitution groups (element references are not
permitted) or attributes; furthermore, they MUST not be nillable.
Non-elements can be present too, as long as they are contained inside an javax.xml.ws.Holder object.
I'm working on a SOAP webservice which features many inputfields using enumeration restrictions.
These enumerations are much like an HTML select/option setup; I expect a certain value to be returned but the label of that value should be exposed using the WSDL as well.
An example: the client wishes to add an insurance policy regarding his/her house and thus needs to specify the type of building involved.
<xsd:restriction base="xsd:string">
<xsd:enumeration value="00001" />
<xsd:enumeration value="00002" />
<xsd:enumeration value="00003" />
</xsd:restriction>
However, the client does not yet understand what these values 1, 2 and 3 are. So, something like this:
<xsd:restriction base="xsd:string">
<xsd:enumeration value="00001" label="Brick and mortar" />
<xsd:enumeration value="00002" label="Straw" />
<xsd:enumeration value="00003" label="Aircastle" />
</xsd:restriction>
would be great for the client to be used to display these labels to the consumer.
Is there any standard WSDL annotation/syntax for this construction?
Is there any standard WSDL annotation/syntax for this construction?
I'm afraid not. The XML Schema enumeration is used to constrain a value to be within a specified set of possible values. When your client sends you the request, the element with the restriction type will only be allowed to have (in your case) a value of 00001, 00002 or 00003 or it won't be valid.
The restriction only specifies the values, you can't add labels. You could at best add an <annotation> but that would be just documentation. In the client UI, it would be the responsibility of each client to say that 00001 is actually "Brick and mortar" and that 00002 is "Straw" etc.
If you don't want to do that, and instead want to also return labels, then you need a slightly more complex object, maybe something like this:
<option>
<key>00001</key>
<label>Brick and mortar</label>
</option>
You provide a label and you restrict the key with a schema like:
<xsd:simpleType name="ValuesType">
<xsd:restriction base="xsd:string">
<xsd:enumeration value="00001" />
<xsd:enumeration value="00002" />
<xsd:enumeration value="00003" />
</xsd:restriction>
</xsd:simpleType>
<xsd:complexType name="OptionType">
<xsd:sequence>
<xsd:element name="key" type="ValuesType" />
<xsd:element name="label" type="xsd:string" />
</xsd:sequence>
</xsd:complexType>
You can return a list of options to the clients and they can present it in the interface with key as value and label as the text of options in <select> inputs, while on the request you will get back the selected value (i.e. the selected key).
I'm trying to create a new Service Reference from a WSDL and all of the properties I expect to be DateTime instead of string.
For example, this xsd definition for Contact:
<s:complexType name="Contact">
<s:sequence>
<s:element minOccurs="0" maxOccurs="1" name="Address" type="tns:Address" />
<s:element minOccurs="0" maxOccurs="1" name="Email" type="s:string" />
...
<s:element minOccurs="1" maxOccurs="1" name="BirthDate" type="s:date" />
</s:sequence>
The type of BirthDate is s:date, but the generated type (in Reference.cs) is a string.
internal partial class Contact : object, IExtensibleDataObject, INotifyPropertyChanged
{
[OptionalField]
private MembershipMgmtMediator.Address AddressField;
[OptionalField]
private string EmailField;
private string BirthDateField;
}
If i create a web project and add it as a Web Reference instead of a Service Reference, it correctly becomes a DateTime. I assume that has something to do with the way wsdl.exe and svcutil.exe work behind the scenes, but regardless, I'm stuck on trying to figure out how to correctly get Visual Studio to recognize that this property should be a DateTime.
There is some good info in these questions: How to generate xs:Date in WCF OperationContract parameter and Best practices for DateTime serialization in .NET 3.5.
As Alex states in his comment to the question, WCF does not support xs:date types. However, it is perhaps more accurate to say that the default DataContractSerializer does not support that type, while the above questions indicate that the XmlSerializer can handle it.
See this link for a DataContractSerializer against XmlSerializer comparison.
If I run:
svcutil http://my_web_site?wsdl /ser:XmlSerializer /d:C:\temp
Then a WSDL fragment like this:
<s:complexType name="Contact">
<s:sequence>
<s:element minOccurs="1" maxOccurs="1" name="BirthDate" type="s:date" />
</s:sequence>
</s:complexType>
Has this class generated:
/// <remarks/>
[System.CodeDom.Compiler.GeneratedCodeAttribute("svcutil", "4.0.30319.1")]
[System.SerializableAttribute()]
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlTypeAttribute(Namespace="http://tempuri.org/")]
public partial class Contact
{
private System.DateTime birthDateField;
/// <remarks/>
[System.Xml.Serialization.XmlElementAttribute(DataType="date", Order=0)]
public System.DateTime BirthDate
{
get
{
return this.birthDateField;
}
set
{
this.birthDateField = value;
}
}
}
That svcutil invocation produces two files: Service1.cs and output.config. If I include the code file in the project and add the system.serviceModel bits into the configuration file (i.e., web.config or app.config) I can then call the service as normal. For example:
Service1SoapClient client = new Service1SoapClient("Service1Soap");
var contact = client.GetContact();
This approach is not without disadvantages. The Service1.cs file is markedly different if generated without the /ser:XmlSerializer parameter, where you will get additional classes such as WebMethodNameRequest, WebMethodNameRequestBody, WebMethodNameReponse, WebMethodNameReponseBody and so on. If these classes are important in your interactions with the service, my approach may not work for you.
Edit:
In terms of nullable properties, there is some good information in this question: svcutil.exe - Proxy generated not allowing for nullable fields
To get a property nullable in the generated proxy class, the nillable field needs to be set in the WSDL. So something like this:
<s:element minOccurs="0" maxOccurs="1" name="SomeProperty" type="s:date" nillable="true" />
Would generate a property called public System.Nullable<System.DateTime> SomeProperty in the proxy class.
However in your case you can use the SomePropertySpecified property to indicate the presence or absence of the property. These kinds of properties are generated when you have minOccurs="0".
In terms of date formatting I'm not sure. xs:date values are intended to be yyyy-mm-dd with optional timezone information (w3.org). If Oracle is expecting dates in a different format then I wonder how they can be xs:date values at all.
Is there any documentation or other information you can provide regarding the service you are trying to consume?
Edit 2:
I am a little unclear on exactly what "Dates must be in the database format." means in the Oracle docs. If the type is an xs:date then serializing them to the database format would surely mean that it was no longer an xs:date?
Still, there are some things you try in that regard:
Force XmlSerializer to serialize DateTime as 'YYYY-MM-DD hh:mm:ss'
http://www.codeproject.com/Articles/43237/How-to-Implement-IXmlSerializable-Correctly
You may need to simply experiment sending a few queries to the web service to see just how this date business affects things.
Are you sure those *IsSpecified parameters aren't there? To use my Contact class above as the example, minOccurs=0 on the BirthDate property would give the Contact class an extra property called BirthDateIsSpecified.
Although I believe nick_w's answer covers the question quite well (and I'm awarding him the bounty), I'm providing the solution I'm going to use in my specific case, where just using XmlSerializer isn't enough. In the end, I think I'm going to go with an extension that converts DateTime objects to string, using a custom format specifier.
public static class SoapUtils
{
public static string ToOraDate( this DateTime? dt )
{
return dt != null ? dt.Value.ToString("dd-MMM-yyyy",
CultureInfo.InvariantCulture) :
}
}
// Calling a service
someDate = DateTime.Now;
service.SomeMethod( someDate.ToOraDate() );
While this is not a real solution, I think that it may work as a workaround. It is dirty and ugly, and I know that, but it may be better than having String in your code.
Since your own classes (like Address) are properly processed, you could build a simple wrapper around Date class that you would include in your project and schema. The class would have only a Date property or a field and a getter to it.