I use bean-validation in my project and I'd like to write a custom validator for an existing constraint annotation.
For example I have a class that represents a date/time named CustomDateTime. In a class that uses this class as for example a date of birth I'd like to annotate the field with #Past:
public class Person
{
#Past
private CustomDateTime dateOfBirth;
}
I then create a custom validator by implementing ConstraintValidator<Past, CustomDateTime>.
This however doesn't work, since the validation implementation has no knowledge of the custom validator. It then throws: javax.validation.UnexpectedTypeException: No validator could be found for type: com.example.CustomDateTime.
I know that you usually create a separate annotation like this:
#Target({ElementType.FIELD})
#Retention(RetentionPolicy.RUNTIME)
#Constraint(validatedBy = {CustomDateTimePastValidator.class})
public #interface Past
{
....
}
But that seems like double code to me ;-)
How can I register the custom validator to be used with #Past?
You can define an XML-based constraint mapping which adds your constraint validator for the existing #Past constraint:
<?xml version="1.0" encoding="UTF-8"?>
<constraint-mappings
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://jboss.org/xml/ns/javax/validation/mapping validation-mapping-1.0.xsd"
xmlns="http://jboss.org/xml/ns/javax/validation/mapping">
<constraint-definition annotation="javax.validation.constraints.Past">
<validated-by include-existing-validators="true">
<value>com.acme.CustomDateTimePastValidator</value>
</validated-by>
</constraint-definition>
</constraint-mappings>
Then either reference this mapping in your validation.xml:
<?xml version="1.0" encoding="UTF-8"?>
<validation-config
xmlns="http://jboss.org/xml/ns/javax/validation/configuration"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://jboss.org/xml/ns/javax/validation/configuration">
<constraint-mapping>/path/to/constraint-mapping.xml</constraint-mapping>
</validation-config>
Or you add it during bootstrapping your validator:
InputStream mappingStream = ...;
Validator validator = Validation
.byDefaultProvider()
.configure()
.addMapping( mappingStream )
.buildValidatorFactory()
.getValidator();
Related
How can I validate the below class using validator (JSR303) API? This should be done using Hibernate Validator API.
Suppose TesterBatters class itself has some validation. How can I validate those?
public class Example {
private String jseId;
private String jseType;
private String jseName;
private Double jsePpu;
private TesterBatters jseBatters;
private List<TesterToppin> jseTopping;
public String getTesterId() {
return jseId;
}
}
You basically have to add constraint annotations such as #NotNull, #Size etc. to the elements of your model (i.e. the properties and/or classes) and perform a validation of these constraints at a suitable point of time (e.g. when persisting objects or processing data entered by the user into a GUI) using the javax.validation.Validator API.
To recursively apply a validation to referenced objects, use the #Valid annotation.
I recommend to have a look into the Hibernate Validator reference guide which explains in detail how to work with Bean Validation.
Here's the XML:
<?xml version="1.0" encoding="utf-8" ?>
<SAPPHIRE xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<TRANSACTION-CODE>NEW</TRANSACTION-CODE>
<CUSTOMER-NUMBER>100398598</CUSTOMER-NUMBER>
<CUSTOMER-NAME>CART DUDE</CUSTOMER-NAME>
<ACCOUNT-TYPE />
<PERSON FNAME="CART" LNAME="DUDE" RESPONSIBLITY="CART DUDE" />
<SOURCE>cplestore</SOURCE>
<TRAN-REFERENCE>13374470</TRAN-REFERENCE>
<ORDER>
<ORDER-NUMBER NUMBER="00241662693" REFERENCE="13374470">
<PRODUCT-CODE>DLP99022L</PRODUCT-CODE>
<START-DATE>2011-4-6 00:00:00.0</START-DATE>
<EXPIRE-DATE>2011-4-11 00:00:00.0</EXPIRE-DATE>
<MAX-USERS>1</MAX-USERS>
<ALLOWED-USERS>1</ALLOWED-USERS>
<PERSON FNAME="CART" LNAME="DUDE" RESPONSIBLITY="CART DUDE" />
</ORDER-NUMBER>
</ORDER>
</SAPPHIRE>
I have the DTO as:
public class Sapphire : IXmlSerializable
{
public XmlSchema GetSchema()
{
return null;
}
public void ReadXml(XmlReader reader)
{
throw new NotImplementedException();
}
public void WriteXml(XmlWriter writer)
{
throw new NotImplementedException();
}
}
Implementing IXmlSerializable is fairly tricky and potentially error prone (for example you need to make sure that your code correctly handles things like comments). For this example you should just be able to use XSD.exe to generate an appropriate class that uses attributes to control the xml serialisation.
You should use XSD.exe to generate a schema for your example xml fragment (which you ay need to tweak - if you hav an existing XSD schema then skip this step), then use it again to generate a class to use for serialisation.
If you really want to implement IXmlSerializable then try the following resources:
How to Implement IXmlSerializable Correctly (CodeProject)
Proper way to implement IXmlSerializable? (StackOverflow)
I have a custom class declared as follows (in vb.net)
<Serializable()>
Public Class NumInfo
Public n As String
Public f As Integer
Public fc As char()
Public t As Integer
Public tc As char()
Private validFlag As Boolean = True
Public Sub New()
End Sub
'I also have public properties(read/write) for all the public variables
End Class
In my service.asmx codebehind class I have a webmethod as follows:
Public Function ConvertTo(ByVal info As NumInfo) As String
Return mbc(info)<br>'mbc is another function defined in my service.asmx "service" class
End Function
The problem is that when I start debugging it to test it, the page that I get does not contain any fields where I could input the values for the public fields of numInfo. How do I initialise the class? There is no "Invoke" button either. All I see are soap details as below:
ConvertToTestThe test form is only
available for methods with primitive
types as parameters.SOAP 1.1The
following is a sample SOAP 1.1 request
and response. The placeholders
shown need to be replaced with actual
values.POST /Converter/BC.asmx
HTTP/1.1Host:
localhostContent-Type: text/xml;
charset=utf-8Content-Length:
lengthSOAPAction:
"http://Services/ConvertTo"<?xml
version="1.0"
encoding="utf-8"?>
<soap:Envelope
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body>
<ConvertTo xmlns="http://Services/">
<info>
<n>string</n>
<f>int</f>
<fc>
<char>char</char>
<char>char>/char>
</fc>..etc..
What am I doing wrong? For the record I tried replacing char() with string to see if it was the array causing problems but that didn't help either. I'm fairly new to web services. I tried replacing the custom object parameter with a primitive parameter just to check how things worked and it rendered a page with an input field and invoke button. I just can't seem to get it working with custom object. Help!
as the message says "The test form is only available for methods with primitive types as parameters." meaning string, bool, int etc.
I find it is simple enough to set up a test page where I can define my object and pass it to the web method for debugging purposes.
I have a form where I have two fields that I can add as much as I can. Think of it as like the upload file in gmail where I can add 1,2,3... files to upload only that I have two fields.
I am not so sure how this will check out using a SimpleFormController in Spring. Will the Spring Controller bind the them automatically?
My command class looks like this:
public class Course {
private long ID;
private String Owner;
private String Title;
private String Learning Objective;
//I am not so sure how this will be bound
private List<LearningActivity> learningActivities;
//accessor methods
}
public class LearningActivity {
private String Description;
private String link;
//accessor methods
}
I would suggest you to use Annotation-based Spring controllers as SimpleFormController is deprecated as of spring 3.0
If you are using annotations based
controller then their is no need to
extend any class or implement any
interface. The only thing you need to
do to make your simple java class to
become a Spring controller is to add
the #Controller annotation to it.
Example here
Also for handling dynamic fields in the form, it is better that you use Spring Form Tags
Example here
Edit: check 5.4.2.1. Registering additional custom PropertyEditors in spring docs, it has an example of what u want
I have a dynamic Class that is a Value Object that is used to pass arguments to a WebService. It has two public properties:
package
{
[Bindable]
public dynamic class WebServiceCriteria
{
public var property1:String;
public var property2:String;
}
}
I set these two properties in one part of my application:
var myCriteria:WebServiceCriteria = new WebServiceCriteria();
myCriteria.property1 = "x";
myCriteria.property2 = "y";
Then I added other - dynamic - properties at another point in my application:
myCriteria.property3 = "z";
However, when I pass the instance to the WebService as the arguments, the original two public properties are not sent (as I can see in Fiddler), even though they have values. But, I can see them as properties of my Class instance in the debugger just prior to the send().
operation.arguments = {args: myCriteria};
operation.send(); // only property3 is sent
Why are those two properties not sent?
Here is an example of the SOAP request sent to the WebService:
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<SOAP-ENV:Body SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<intf:webservice_controller xmlns:intf="http://childDir.parentDir">
<args xsi:type="apachesoap:Map" xmlns:apachesoap="http://xml.apache.org/xml-soap">
<item>
<key xsi:type="xsd:string">property1</key>
<value xsi:type="xsd:string"></value>
</item>
<item>
<key xsi:type="xsd:string">property2</key>
<value xsi:type="xsd:string"></value>
</item>
<item>
<key xsi:type="xsd:string">property3</key>
<value xsi:type="xsd:string">z</value>
</item>
</args>
</intf:webservice_controller>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
This behavior is documented in Flex 3.0 manuals. See Dynamic Classes for more information. A direct quote:
[...]Methods created in this way, however, do not have access to any private properties or methods of the [example] class. Moreover, even references to public properties or methods of the [example] class must be qualified with either the this keyword or the class name.
Try to add this to your constructor :
package
{
[Bindable]
public dynamic class WebServiceCriteria
{
public var property1:String;
public var property2:String;
function WebServiceCriteria()
{
prototype.property1 = null;
prototype.property2 = null;
}
}
}
... As it seems like only the Objects properties are enumerable
I don't believe you will be able to send an object to a webservice. If you want to send an object you will need to use remote object. To use a webservice you would need to make your object into some kind of xml or soap request. like
var myCriteria:WebServiceCriteria = new WebServiceCriteria();
myCriteria.property1 = "x";
myCriteria.property2 = "y";
operation.send(<request>
<property1>{myCriteria.property1}</property1>
<property2>{myCriteria.property2}</property2>
</request>);
http://livedocs.adobe.com/flex/3/html/help.html?content=data_intro_2.html