i'm new to MOXy and JaxB in general and I'm facing a problem with java.util.Date conversion.
I'm unmarshaling an XML file (which I have no control of) to objects using a mapping file (I can neither manually annotate existing classes nor change them).
My XML mapping file looks like this :
<?xml version="1.0"?>
<xml-bindings
xmlns="http://www.eclipse.org/eclipselink/xsds/persistence/oxm"
version="2.1">
<java-types>
<java-type name="Observation">
<xml-type prop-order="date theoricalTime ci ch cr type" />
<java-attributes>
<xml-element java-attribute="date" xml-path="Date/text()" />
<xml-element java-attribute="theoricalTime" xml-path="TheoricalTime/text()" />
<xml-element java-attribute="ci" xml-path="CIPR/text()" />
<xml-element java-attribute="ch" xml-path="CHPR/text()" />
<xml-element java-attribute="cr" xml-path="CRPR/text()" />
<xml-element java-attribute="type" xml-path="Type/text()" />
</java-attributes>
</java-type>
</java-types>
</xml-bindings>
In the class which I'm marshalling to, properties "date" and "theoricalTime" are of type java.util.Date.
The values from the xml I'm marshalling from are strings with this kind of format : "dd/MM/yyyy HH:mm:ss" ("05/01/2012 16:36:24"). I also have some fields with only a time value "HH:mm:ss" ("14:17:33").
Here is the stacktrace I'm getting when unmarshalling the file :
Exception in thread "main" Local Exception Stack:
Exception [EclipseLink-3002] (Eclipse Persistence Services - 2.3.2.v20111125-r10461): org.eclipse.persistence.exceptions.ConversionException
Exception Description: The object [22/01/2009 20:56:29], of class [class java.lang.String], from mapping [org.eclipse.persistence.oxm.mappings.XMLDirectMapping[date-->Date/text()]] with descriptor [XMLDescriptor(Observation --> [DatabaseTable(Observation)])], could not be converted to [class java.util.Calendar].
at org.eclipse.persistence.exceptions.ConversionException.incorrectDateTimeFormat(ConversionException.java:127)
at org.eclipse.persistence.exceptions.ConversionException.incorrectDateTimeFormat(ConversionException.java:133)
at org.eclipse.persistence.internal.oxm.XMLConversionManager.convertStringToXMLGregorianCalendar(XMLConversionManager.java:703)
at org.eclipse.persistence.internal.oxm.XMLConversionManager.convertStringToDate(XMLConversionManager.java:1111)
at org.eclipse.persistence.internal.oxm.XMLConversionManager.convertObjectToUtilDate(XMLConversionManager.java:804)
at org.eclipse.persistence.internal.oxm.XMLConversionManager.convertObject(XMLConversionManager.java:165)
at org.eclipse.persistence.internal.databaseaccess.DatasourcePlatform.convertObject(DatasourcePlatform.java:160)
at org.eclipse.persistence.oxm.mappings.XMLDirectMapping.getAttributeValue(XMLDirectMapping.java:293)
at org.eclipse.persistence.internal.oxm.XMLDirectMappingNodeValue.endElement(XMLDirectMappingNodeValue.java:182)
at org.eclipse.persistence.oxm.record.UnmarshalRecord.endElement(UnmarshalRecord.java:823)
at com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser.endElement(AbstractSAXParser.java:601)
at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl.scanEndElement(XMLDocumentFragmentScannerImpl.java:1774)
at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl$FragmentContentDriver.next(XMLDocumentFragmentScannerImpl.java:2930)
at com.sun.org.apache.xerces.internal.impl.XMLDocumentScannerImpl.next(XMLDocumentScannerImpl.java:648)
at com.sun.org.apache.xerces.internal.impl.XMLNSDocumentScannerImpl.next(XMLNSDocumentScannerImpl.java:140)
at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl.scanDocument(XMLDocumentFragmentScannerImpl.java:510)
at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:807)
at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:737)
at com.sun.org.apache.xerces.internal.parsers.XMLParser.parse(XMLParser.java:107)
at com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser.parse(AbstractSAXParser.java:1205)
at com.sun.org.apache.xerces.internal.jaxp.SAXParserImpl$JAXPSAXParser.parse(SAXParserImpl.java:522)
at org.eclipse.persistence.internal.oxm.record.XMLReader.parse(XMLReader.java:157)
at org.eclipse.persistence.internal.oxm.record.SAXUnmarshaller.unmarshal(SAXUnmarshaller.java:753)
at org.eclipse.persistence.internal.oxm.record.SAXUnmarshaller.unmarshal(SAXUnmarshaller.java:333)
at org.eclipse.persistence.internal.oxm.record.SAXUnmarshaller.unmarshal(SAXUnmarshaller.java:320)
at org.eclipse.persistence.internal.oxm.record.SAXUnmarshaller.unmarshal(SAXUnmarshaller.java:280)
at org.eclipse.persistence.oxm.XMLUnmarshaller.unmarshal(XMLUnmarshaller.java:306)
at org.eclipse.persistence.jaxb.JAXBUnmarshaller.unmarshal(JAXBUnmarshaller.java:115)
at Main.Test(Main.java:97)
at Main.main(Main.java:35)
My question is : Is it possible to specify types conversions inside the mapping file using MOXy's external metadata ? How can I handle datetime and time with the formats specified above and map them to Date fields ?
(I secretly hope Blaise Doughan is reading this.)
Thanks in advance for your help !
The following demonstrates how you can use an XmlAdapter with MOXy's external mapping document to achieve the results that you are looking for:
DateAdapter
Since your date/time data is in the following format dd/MM/yyyy HH:mm:ss you will need to use an XmlAdapter like the following:
package forum8745305;
import java.text.SimpleDateFormat;
import java.util.Date;
import javax.xml.bind.annotation.adapters.XmlAdapter;
public class DateAdapter extends XmlAdapter<String, Date> {
private SimpleDateFormat dateFormat = new SimpleDateFormat("dd/MM/yyyy HH:mm:ss");
#Override
public String marshal(Date v) throws Exception {
return dateFormat.format(v);
}
#Override
public Date unmarshal(String v) throws Exception {
return dateFormat.parse(v);
}
}
oxm.xml
This is normally specified on your domain model using the #XmlJavaTypeAdapter annotation, but since you are using MOXy's external metadata document you can specify it as follows. I have specified it at the package level so that it will apply to all fields/properties of type java.util.Date belonging to domain classes in that package:
<?xml version="1.0"?>
<xml-bindings
xmlns="http://www.eclipse.org/eclipselink/xsds/persistence/oxm"
version="2.1"
package-name="forum8745305">
<xml-java-type-adapters>
<xml-java-type-adapter value="forum8745305.DateAdapter" type="java.util.Date"/>
</xml-java-type-adapters>
<java-types>
<java-type name="Observation">
<xml-type prop-order="date theoricalTime ci ch cr type" />
<xml-root-element/>
<java-attributes>
<xml-element java-attribute="date" xml-path="Date/text()"/>
<xml-element java-attribute="theoricalTime" xml-path="TheoricalTime/text()" />
<xml-element java-attribute="numeroTrain" xml-path="NumeroTrain/text()" />
<xml-element java-attribute="ci" xml-path="CIPR/text()" />
<xml-element java-attribute="ch" xml-path="CHPR/text()" />
<xml-element java-attribute="cr" xml-path="CRPR/text()" />
<xml-element java-attribute="type" xml-path="Type/text()" />
</java-attributes>
</java-type>
</java-types>
</xml-bindings>
Observation
Based on your question, below is what your domain class might look like:
package forum8745305;
import java.util.Date;
public class Observation {
private Date date;
private Date theoricalTime;
private String numeroTrain;
private String ci;
private String ch;
private String cr;
private String type;
public Date getDate() {
return date;
}
public void setDate(Date date) {
this.date = date;
}
public Date getTheoricalTime() {
return theoricalTime;
}
public void setTheoricalTime(Date theoricalTime) {
this.theoricalTime = theoricalTime;
}
public String getNumeroTrain() {
return numeroTrain;
}
public void setNumeroTrain(String numeroTrain) {
this.numeroTrain = numeroTrain;
}
public String getCi() {
return ci;
}
public void setCi(String ci) {
this.ci = ci;
}
public String getCh() {
return ch;
}
public void setCh(String ch) {
this.ch = ch;
}
public String getCr() {
return cr;
}
public void setCr(String cr) {
this.cr = cr;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
}
Demo
The following code can be used to run the example:
package forum8745305;
import java.io.File;
import java.util.HashMap;
import java.util.Map;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
import org.eclipse.persistence.jaxb.JAXBContextFactory;
public class Demo {
public static void main(String[] args) throws Exception {
Map<String, Object> properties = new HashMap<String, Object>(1);
properties.put(JAXBContextFactory.ECLIPSELINK_OXM_XML_KEY, "forum8745305/oxm.xml");
JAXBContext jc = JAXBContext.newInstance(new Class[] {Observation.class}, properties);
Unmarshaller unmarshaller = jc.createUnmarshaller();
File xml = new File("src/forum8745305/input.xml");
Observation observation = (Observation) unmarshaller.unmarshal(xml);
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.marshal(observation, System.out);
}
}
Input/Output
<?xml version="1.0" encoding="UTF-8"?>
<observation>
<Date>05/01/2012 16:36:24</Date>
<TheoricalTime>01/02/2012 12:34:45</TheoricalTime>
</observation>
For More Information
http://blog.bdoughan.com/2011/05/specifying-eclipselink-moxy-as-your.html
http://blog.bdoughan.com/2010/12/extending-jaxb-representing-annotations.html
http://blog.bdoughan.com/search/label/XmlAdapter
UPDATE
You can also specify XmlAdapters at the property level. This means you could have a different XmlAdapter for each of your Date properties if you wanted to.
<?xml version="1.0"?>
<xml-bindings
xmlns="http://www.eclipse.org/eclipselink/xsds/persistence/oxm"
version="2.1"
package-name="forum8745305">
<java-types>
<java-type name="Observation">
<xml-type prop-order="date theoricalTime ci ch cr type" />
<xml-root-element/>
<java-attributes>
<xml-element java-attribute="date" xml-path="Date/text()">
<xml-java-type-adapter value="forum8745305.DateAdapter"/>
</xml-element>
<xml-element java-attribute="theoricalTime" xml-path="TheoricalTime/text()">
<xml-java-type-adapter value="forum8745305.DateAdapter"/>
</xml-element>
<xml-element java-attribute="numeroTrain" xml-path="NumeroTrain/text()" />
<xml-element java-attribute="ci" xml-path="CIPR/text()" />
<xml-element java-attribute="ch" xml-path="CHPR/text()" />
<xml-element java-attribute="cr" xml-path="CRPR/text()" />
<xml-element java-attribute="type" xml-path="Type/text()" />
</java-attributes>
</java-type>
</java-types>
</xml-bindings>
Related
We use Jaxb (jaxb-api 2.2.5) to generate a Java class from an XSD. The 'someField' element has a nillable='true' attribute and an (implicit) minoccurs='1'. There is also an optional 'order' attribute.
When we set the order attribute on someField, but no value, JAXB will generate the XML element in the request without nill='true' and this is not accepted by the XSD and results in a SOAP fault.
The XSD for the field:
<xs:element name="someField" nillable="true">
<xs:complexType>
<xs:simpleContent>
<xs:extension base="iata:AlphaNumericStringLength1to19">
<xs:attribute name="order" type="xs:integer" use="optional"/>
</xs:extension>
</xs:simpleContent>
</xs:complexType>
</xs:element>
Jaxb translates this to the following field on our Java class:
#XmlElement(required = true, nillable = true)
protected SomeParentType.SomeField someField;
The SomeField class looks like this:
public static class SomeField{
#XmlValue
protected String value;
#XmlAttribute
protected BigInteger order;
// getters + setters
}
When we set the order ATTRIBUTE to 2 (for example), and set nothing for the value, JAXB will generate this:
<pay1:someField order="2"/>
This is not valid according to the XSD and it results in a SOAP fault when we send it.
This does work:
<pay1:someField xsi:nil="true" order="2"/>
Do you know how we can get JAXB be to generate the latter? And is JAXB actually wrong in generating the nil-less version?
And is JAXB actually wrong in generating the nil-less version?
Let me get back to you on this.
Do you know how we can get JAXB be to generate the latter?
Below is what you can do
Java Model
SomeParentType
To get the behaviour you are looking for with existing JAXB libraries the domain model needs to be of the following form:
import java.math.BigInteger;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.annotation.*;
#XmlRootElement
public class SomeParentType {
#XmlElementRef(name="someField")
protected JAXBElement<SomeParentType.SomeField> someField;
public static class SomeField{
#XmlValue
protected String value;
#XmlAttribute
protected BigInteger order;
// getters + setters
}
}
Registry
To go along with the #XmlElementRef we need to have an #XmlElementDecl on a class annotated with #XmlRegistry.
import javax.xml.namespace.QName;
import javax.xml.bind.*;
import javax.xml.bind.annotation.*;
#XmlRegistry
public class Registry {
#XmlElementDecl(name="someField")
public JAXBElement<SomeParentType.SomeField> createSomeField(SomeParentType.SomeField someField) {
return new JAXBElement(new QName("someField"), SomeParentType.SomeField.class, someField);
}
}
Demo Code
Below is some demo code to exercise your use case:
import javax.xml.bind.*;
import java.math.BigInteger;
public class Demo {
public static void main(String[] args) throws Exception {
// Create the JAXBContext to bring in the Registry
JAXBContext jc = JAXBContext.newInstance(SomeParentType.class, Registry.class);
// Create the instance of SomeField
SomeParentType.SomeField sf = new SomeParentType.SomeField();
sf.order = new BigInteger("1");
// Wrap the SomeField in a JAXBElement & specify the nil aspect
Registry registry = new Registry();
JAXBElement<SomeParentType.SomeField> jaxbElement = registry.createSomeField(sf);
jaxbElement.setNil(true);
SomeParentType spt = new SomeParentType();
spt.someField = jaxbElement;
// Marshal the domain model to XML
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.marshal(spt, System.out);
}
}
Output
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<someParentType>
<someField xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" order="1" xsi:nil="true"/>
</someParentType>
I need to use <any>element in my xsd for scalability. So i used xsd as like below.
<complexType name="AddInput">
<sequence>
<element name="First" type="int"></element>
<element name="Sec" type="int"></element>
<any processContents="lax" namespace="##any" minOccurs="0" maxOccurs="unbounded"></any>
</sequence>
</complexType>
I have defined a complex object to place into the <any> placeholder, with ObjectFactory (#XMLRegistry, #XmlElementDecl) But still if i run below code, i am getting
org.apache.xerces.dom.ElementNSImpl
instead of JAXBElementObject. I searched in google, i see that JAXBContext should know about the schema. But i am not sure, how to make JAXBContext know my complex object. Any idea would be helpful.
List<Object> elemList = (List<Object>)input.getAny();
for(Object elem : elemList){
System.out.println(elem.getClass());
}
If you have a JAX-RS method like the following the JAXBContext used will be equivalent to making the following call JAXBContext.newInstance(Foo)
#GET
#Produces(MediaType.APPLICATION_XML)
#Path("{id}")
public Foo read(#PathParam("id") long id) {
return entityManager.find(Foo.class, id);
}
If you want the JAXBContext to be aware of all the classes you generated from the XML schema you can associate a JAXBContext with the domain object using a ContextResolver.
import java.io.*;
import java.util.*;
import javax.ws.rs.Produces;
import javax.ws.rs.ext.*;
import javax.xml.bind.*;
import org.eclipse.persistence.jaxb.JAXBContextFactory;
#Provider
#Produces(MediaType.APPLICATION_XML)
public class FooContextResolver implements ContextResolver<JAXBContext> {
private JAXBContext jc;
public FooContextResolver() {
try {
jc = JAXBContext.newInstance("com.example.foo");
} catch(JAXBException e) {
throw new RuntimeException(e);
}
}
public JAXBContext getContext(Class<?> clazz) {
if(Foo.class == clazz) {
return jc;
}
return null;
}
}
Example
Flexible marshalling with JAXB
you need to set :
jaxb.additionalContextClasses
see : https://stackoverflow.com/a/55485843/1634131
I've been using Moxy to successfully marshall / unmarshall complex xml types into a more simple java Structure. In particular, I'm working with ISO Pain 20022 messages and there are a number of fields that are present in the XML that we don't care about:
<?xml version="1.0" encoding="UTF-8"?>
<iso:Document xmlns:iso="urn:iso:std:iso:20022:tech:xsd:pain.001.001.04" >
<iso:CstmrCdtTrfInitn>
<iso:GrpHdr>
<iso:MsgId>OriginalMessageID</iso:MsgId>
<iso:CreDtTm>2013-05-29T20:02:22.615</iso:CreDtTm>
<iso:NbOfTxs>1</iso:NbOfTxs>
<iso:InitgPty/>
</iso:GrpHdr>
<iso:PmtInf>
...
</iso:Document>
Here is my oxm bindings file piece:
<xml-element java-attribute="messageId" xml-path="iso:CstmrCdtTrfInitn/iso:GrpHdr/iso:MsgId/text()"/>
<xml-element java-attribute="creationDateTime" xml-path="iso:CstmrCdtTrfInitn/iso:GrpHdr/iso:CreDtTm/text()"/>
I need to generate the additional two xml elements iso:NbOfTxs and iso:InitgPty which will always be the same and there is no corresponding property for these on the java class that is generating the xml.
Is this possible?
Thanks.
I am still working on this use case. Below is the XML I am currently able to generate (I recognize that it's not correct).
Output
<?xml version="1.0" encoding="UTF-8"?>
<iso:Document xmlns:iso="urn:iso:std:iso:20022:tech:xsd:pain.001.001.04">
<iso:CstmrCdtTrfInitn>
<iso:GrpHdr>
<iso:MsgId>OriginalMessageID</iso:MsgId>
</iso:GrpHdr>
</iso:CstmrCdtTrfInitn>
<iso:CstmrCdtTrfInitn>
<iso:GrpHdr>
<iso:CreDtTm>2013-05-29T20:02:22.615</iso:CreDtTm>
<iso:NbOfTxs>1</iso:NbOfTxs>
<iso:InitgPty/>
</iso:GrpHdr>
</iso:CstmrCdtTrfInitn>
</iso:Document>
Document
Below is a simplified version of your domain model:
import java.util.Date;
public class Document {
private String messageId;
private Date creationDateTime;
}
oxm.xml
In the metadata below I'm trying to use an XmlAdapter to convert the Date property into a more complex object that can write out the other 2 XML elements.
<?xml version="1.0"?>
<xml-bindings
xmlns="http://www.eclipse.org/eclipselink/xsds/persistence/oxm"
package-name="forum16839007">
<xml-schema
namespace="urn:iso:std:iso:20022:tech:xsd:pain.001.001.04"
element-form-default="QUALIFIED">
<xml-ns prefix="iso" namespace-uri="urn:iso:std:iso:20022:tech:xsd:pain.001.001.04"/>
</xml-schema>
<java-types>
<java-type name="Document" xml-accessor-type="FIELD">
<xml-root-element name="Document"/>
<java-attributes>
<xml-element java-attribute="messageId" xml-path="iso:CstmrCdtTrfInitn/iso:GrpHdr/iso:MsgId/text()"/>
<xml-element java-attribute="creationDateTime" xml-path=".">
<xml-java-type-adapter value="forum16839007.ExtraAdapter"/>
</xml-element>
</java-attributes>
</java-type>
</java-types>
</xml-bindings>
ExtraAdapter
Here is the XmlAdapter that converts a Date into a more complex object.
import java.util.Date;
import javax.xml.bind.annotation.adapters.XmlAdapter;
import org.eclipse.persistence.oxm.annotations.XmlPath;
public class ExtraAdapter extends XmlAdapter<ExtraAdapter.Extra, Date>{
public static class Extra {
#XmlPath("iso:CstmrCdtTrfInitn/iso:GrpHdr/iso:CreDtTm/text()")
public Date creationDateTime;
#XmlPath("iso:CstmrCdtTrfInitn/iso:GrpHdr/iso:NbOfTxs/text()")
public final int NbOfTxs = 1;
#XmlPath("iso:CstmrCdtTrfInitn/iso:GrpHdr/iso:InitgPty/text()")
public final Empty initgPty = new Empty();
}
public static class Empty {
}
#Override
public Date unmarshal(Extra extra) throws Exception {
return extra.creationDateTime;
}
#Override
public Extra marshal(Date date) throws Exception {
Extra extra = new Extra();
extra.creationDateTime = date;
return extra;
}
}
Demo
import java.io.File;
import java.util.*;
import javax.xml.bind.*;
import org.eclipse.persistence.jaxb.JAXBContextProperties;
public class Demo {
public static void main(String[] args) throws Exception {
Map<String, Object> properties = new HashMap<String, Object>(1);
properties.put(JAXBContextProperties.OXM_METADATA_SOURCE, "forum16839007/oxm.xml");
JAXBContext jc = JAXBContext.newInstance(new Class[] {Document.class}, properties);
Unmarshaller unmarshaller = jc.createUnmarshaller();
File xml = new File("src/forum16839007/input.xml");
Document document = (Document) unmarshaller.unmarshal(xml);
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.marshal(document, System.out);
}
}
Using GWT 2.5.0,
I would like to use Client side validation and Editors. I encounter the following error when trying to pass the ConstraintViolation java.util.Set to the EditorDriver as follows.
Validator a = Validation.buildDefaultValidatorFactory().getValidator();
Set<ConstraintViolation<Person>> b = a.validate(person);
editorDriver.setConstraintViolations(b);
The method setConstraintViolations(Iterable<ConstraintViolation<?>>) in the type EditorDriver<Person> is not applicable for the arguments (Set<ConstraintViolation<Person>>)
The only somewhat relevant post I could find was Issue 6270!
Below is an Example which brings up a PopUpDialog with a Person Editor that allows you to specify a name and validate it against your annotations. Commenting out the personDriver.setConstraintViolations(violations); line in the PersonEditorDialog will allow you to run the example.
I don't have enough reputation points to post the image of the example.
Classes
Person
public class Person {
#NotNull(message = "You must have a name")
#Size(min = 3, message = "Your name must contain more than 3 characters")
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
PersonEditorDialog
public class PersonEditorDialog extends DialogBox implements Editor<Person> {
private static PersonEditorDialogUiBinder uiBinder = GWT
.create(PersonEditorDialogUiBinder.class);
interface PersonEditorDialogUiBinder extends
UiBinder<Widget, PersonEditorDialog> {
}
private Validator validator;
public PersonEditorDialog() {
validator = Validation.buildDefaultValidatorFactory().getValidator();
setWidget(uiBinder.createAndBindUi(this));
}
interface Driver extends SimpleBeanEditorDriver<Person, PersonEditorDialog> {
};
#UiField
ValueBoxEditorDecorator<String> nameEditor;
#UiField
Button validateBtn;
private Driver personDriver;
#UiHandler("validateBtn")
public void handleValidate(ClickEvent e) {
Person created = personDriver.flush();
Set<ConstraintViolation<Person>> violations = validator
.validate(created);
if (!violations.isEmpty() || personDriver.hasErrors()) {
StringBuilder violationMsg = new StringBuilder();
for (Iterator<ConstraintViolation<Person>> iterator = violations.iterator(); iterator.hasNext();) {
ConstraintViolation<Person> constraintViolation = (ConstraintViolation<Person>) iterator
.next();
violationMsg.append(constraintViolation.getMessage() + ",");
}
Window.alert("Detected violations:" + violationMsg);
personDriver.setConstraintViolations(violations);
}
}
#Override
public void center() {
personDriver = GWT.create(Driver.class);
personDriver.initialize(this);
personDriver.edit(new Person());
super.center();
}
}
SampleValidationFactory
public final class SampleValidationFactory extends AbstractGwtValidatorFactory {
/**
* Validator marker for the Validation Sample project. Only the classes and
* groups listed in the {#link GwtValidation} annotation can be validated.
*/
#GwtValidation(Person.class)
public interface GwtValidator extends Validator {
}
#Override
public AbstractGwtValidator createValidator() {
return GWT.create(GwtValidator.class);
}
}
EditorValidationTest
public class EditorValidationTest implements EntryPoint {
/**
* This is the entry point method.
*/
public void onModuleLoad() {
PersonEditorDialog personEditorDialog = new PersonEditorDialog();
personEditorDialog.center();
}
}
UiBinder
PersonEditorDialog.ui.xml
<!DOCTYPE ui:UiBinder SYSTEM "http://dl.google.com/gwt/DTD/xhtml.ent">
<ui:UiBinder xmlns:ui="urn:ui:com.google.gwt.uibinder"
xmlns:g="urn:import:com.google.gwt.user.client.ui" xmlns:e="urn:import:com.google.gwt.editor.ui.client">
<ui:style>
.important {
font-weight: bold;
}
</ui:style>
<g:HTMLPanel>
<g:Label>Enter your Name:</g:Label>
<e:ValueBoxEditorDecorator ui:field="nameEditor">
<e:valuebox>
<g:TextBox />
</e:valuebox>
</e:ValueBoxEditorDecorator>
<g:Button ui:field="validateBtn">Validate</g:Button>
</g:HTMLPanel>
</ui:UiBinder>
GWT Module
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE module PUBLIC "-//Google Inc.//DTD Google Web Toolkit 2.5.0//EN"
"http://google-web-toolkit.googlecode.com/svn/tags/2.5.0/distro-source/core/src/gwt-module.dtd">
<module rename-to='editorvalidationtest'>
<inherits name='com.google.gwt.user.User' />
<inherits name='com.google.gwt.user.theme.clean.Clean' />
<inherits name="com.google.gwt.editor.Editor"/>
<!-- Validation module inherits -->
<inherits name="org.hibernate.validator.HibernateValidator" />
<replace-with
class="com.test.client.SampleValidationFactory">
<when-type-is class="javax.validation.ValidatorFactory" />
</replace-with>
<!-- Specify the app entry point class. -->
<entry-point class='com.test.client.EditorValidationTest' />
<!-- Specify the paths for translatable code -->
<source path='client' />
<source path='shared' />
</module>
Libs required on Classpath
hibernate-validator-4.1.0.Final.jar
hibernate-validator-4.1.0.Final-sources.jar
validation-api-1.0.0.GA.jar (in GWT SDK)
validation-api-1.0.0.GA-sources.jar (in GWT SDK)
slf4j-api-1.6.1.jar
slf4j-log4j12-1.6.1.jar
log4j-1.2.16.jar
As discussed in the comments, the following cast was determined to be a valid workaround.
Set<?> test = violations;
editorDriver.setConstraintViolations((Set<ConstraintViolation<?>>) test);
This is what I do over and over again :
List<ConstraintViolation<?>> adaptedViolations = new ArrayList<ConstraintViolation<?>>();
for (ConstraintViolation<Person> violation : violations) {
adaptedViolations.add(violation);
}
editorDriver.setConstraintViolations(adaptedViolations);
The driver has a wild card generic type defined and you can not pass in the typed constraint violations.
I've recompiled some of my code under Java 7 and started testing. Quite soon I've noticed that mechanism I used for serialization of objects to xml stopped working. Luckily this serialization is for temporary session storage purpose so I could remove all old serialized XMLs and start from scratch using xstream instead of XMLEncoder.
I'm curious what have I done wrong or what changed in the XMLEncoder shipped with Java7.
B.java:
import java.util.*;
public class B{
public String s;
public void setS(String s){
this.s = s;
}
public String getS(){
return this.s;
}
public HashSet<String> h = new HashSet<String>();
public void setH(HashSet<String> h){
this.h = h;
}
public HashSet<String> getH(){
return this.h;
}
}
A.java:
import java.util.*;
import java.io.*;
import java.beans.*;
class A{
public A(){
B tmp = new B();
tmp.setS("abc");
HashSet<String>h = new HashSet<String>(Arrays.asList("a", "c"));
tmp.setH(h);
ByteArrayOutputStream bos = new ByteArrayOutputStream();
XMLEncoder e = new XMLEncoder( new BufferedOutputStream(bos) );
e.writeObject( tmp );
e.close();
System.out.println(bos.toString());
}
public static void main(String []arg){
new A();
}
}
Running A under java 1.6.x gives me:
<?xml version="1.0" encoding="UTF-8"?>
<java version="1.6.0_25" class="java.beans.XMLDecoder">
<object class="B">
<void property="h">
<void method="add">
<string>b</string>
</void>
<void method="add">
<string>a</string>
</void>
</void>
<void property="s">
<string>abc</string>
</void>
</object>
</java>
Running A under java 1.7.0_01 gives me:
<?xml version="1.0" encoding="UTF-8"?>
<java version="1.7.0_01" class="java.beans.XMLDecoder">
<object class="B" id="B0">
<void class="B" method="getField">
<string>s</string>
<void method="set">
<object idref="B0"/>
<string>abc</string>
</void>
</void>
</object>
</java>
As you can see the output does not contain any trace of the HashSet h field.
I've done some googling but so far the only similar case that I could find is this post, nothing else.
Thanks in advance for your hints.
You need to make your data members private in Class B and it will work fine. try this code.
private String s;
private HashSet<String> h = new HashSet<String>();
You need to follow java conventions in defining all your classes. XMLEncode will use getter/setter methods to properly convert objects into xml.