How can I create a custom validator for a URL field in Beans Validation 1.0.
But how can I pass the URL string passed via JSON into my constraint validator?
#ValidURL
private URL myUrl;
public class URLValidator implements ConstraintValidator<ValidURL, CharSequence> {...}
#Target({METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER})
#Retention(RUNTIME)
#Constraint(validatedBy = {URLValidator.class})
#Constraint(validatedBy = {})
public #interface ValidURL {
String message() default "must be a valid URL";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
I know the latest Hibernate Validator has a #URL validation but I cannot move to the latest version.
Edit:
With the above I am hitting the following. So my question is how does Hibernate convert the URL type to the CharSequence used by the ConstraintValidator?
javax.validation.UnexpectedTypeException: HV000030: No validator could be found for type: java.net.URL.
Doh, Just realized the Hibernate validator #URL is for String type not java.net.URL
Related
I'm using microprofile 3.2 to call out to a rest webservice that returns a java bean in a Response entity. When I try to extract the bean from the response though I get a
java.lang.ClassCastException: sun.net.www.protocol.http.HttpURLConnection$HttpInputStream incompatible with <class>
error.
E.g.
My bean:
public class MyBean {
private int id;
public int getId() { return id; }
public void setId(final int id) { this.id = id; }
}
REST WS api interface:
#GET
#Path("/{id}")
Response getBean(#PathParam("id") Integer id);
REST implementation class:
public Response getBean(final Integer id) {
MyBean myBean = new Service().getBean(id);
return Response.ok(myBean).build();
}
RestClient:
IBeanResource beanResource =
RestClientBuilder.newBuilder().baseUri(apiURI).build(IBeanResource.class);
Response beanResponse = beanResource.getBean(100);
if (beanResponse.getStatus() == Response.Status.OK.getStatusCode()) {
MyBean bean = (MyBean) beanResponse.getEntity();
}
Error fires on line
MyBean bean = (MyBean) beanResponse.getEntity();
Has anyone seen this before? The documentation isn't great.
Yes that would be the expected behavior. If you inspect the value of beanResponse in debug you will see the Response is of type InboundJaxrsResonse and entity is nothing but of type HttpUrlConnector. Which is why when you try to cast it to your custom bean class it throws ClassCastException. You can try any of the following approach:
you could instead do as below
String jsonString = beanResponse.readEntity(String.class);
The above will give you the JSON response as String and then you may convert it to your respective class using libraries such as gson or jackson of your choice.
In your REST WS api interface instead of returning Response return your model MyBean. As per the Microprofile rest Client spec it states the implementation of Microprofile Rest client must provide a built-in JSON-P entity provider and if it supports JSON-B then it must provide JSON-B entity provider.
microprofile-rest-client-spec-2.0
Thanks for the reply. I'll take a look at the spec again for returning models. I like the idea of capturing the response rather than the model so I have any header or status information too e.g. how would a 404 be handed if the resource could not be found?
I was able to get around this by reading the InputStream and using jsonb to bind to the bean
InputStream is = (InputStream) beanResponse.getEntity();
return jsonb.fromJson(is, MyBean.class);
I'm new to Jersey 2 and JAX-RS, so probably I'm missing something.
What I'm trying to do is a test program to define a coding style in rest services developing.
The test was written in JAVA and uses JERSEY 2.22.2, JDK 1.8.31, MOXY AS JSON Provider.
I defined a Resource with GET methods to support LIST/DETAIL. Due to the size of my POJO, I used some filters and everything was fine.
// 1) First of all I defined the annotation.
#Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD})
#Retention(RetentionPolicy.RUNTIME)
#Documented
#EntityFiltering
public #interface MyDetailView {
public static class Factory extends AnnotationLiteral<MyDetailView>
implements MyDetailView {
private Factory() {
}
public static MyDetailView get() {
return new Factory();
}
}
// 2) Once defined the annotation, I used to
// programmaticaly exclude the list of subItems in the response...
#XmlRootElement
public class MyPojo {
...
//*** THIS SHOULD BE FILTERED IF THE ANNOTATION IS NOT SPECIFIED IN THE RESPONSE ***
#MyDetailView
private List<SubItem> subItems = new ArrayList<SubItem>();
public List<SubItem> getSubItems() {
return subItems;
}
public void setSubItems(List<SubItem> subItems) {
this.subItems = subItems;
}
}
// 3) I registered the EntityFilteringFeature
public class ApplicationConfig extends ResourceConfig {
public ApplicationConfig() {
....
register(EntityFilteringFeature.class);
}
// 4) Finally, I wrote the code to include/exclude the subItems
/*
The Resource class has getCollection() and getItem() methods...
getCollection() adds the annotation only if filterStyle="detail"
getItem() always add the annotation
*/
#Path(....)
#Produces(MediaType.APPLICATION_JSON)
#Consumes(MediaType.APPLICATION_JSON)
public class MyResource extends SecuredResource {
//filterStyle -> "detail" means MyDetailAnnotation
#GET
public Response getCollection(
#QueryParam("filterStyle") String filterStyle,
#Context UriInfo uriInfo) {
//THIS CODE AFFECTS THE RESPONSE
boolean detailedResponse = "detail".equals(filterStyle);
Annotation[] responseAnnotations = detailedResponse
? new Annotation[0]
: new Annotation[]{MyDetailView.Factory.get()};
//pojo collection...
MyPagedCollection myCollection = new MyPagedCollection();
//.....
ResponseBuilder builder = Response.ok();
return builder.entity(myCollection, responseAnnotations).build();
}
#GET
#Path("/{id}")
public Response getItem(#PathParam("{id}") String idS, #Context UriInfo uriInfo) {
MyPOJO pojo = ...
Annotation[] responseAnnotations = new Annotation[]{MyDetailView.Factory.get()};
return Response.ok().entity(pojo, responseAnnotations).build();
}
}
After the first test, I tried to use the SelectableEntityFilteringFeature to allow the client to ask for specific fields in the detail, so I changed the ApplicationConfig
public class ApplicationConfig extends ResourceConfig {
public ApplicationConfig() {
....
register(EntityFilteringFeature.class);
register(SelectableEntityFilteringFeature.class);
property(SelectableEntityFilteringFeature.QUERY_PARAM_NAME, "fields");
}
and I've add the "fields" QueryParam to the Resource getItem() method...
#GET
#Path("/{id}")
public Response getDetail(#PathParam({id}) String id,
#QueryParam("fields") String fields,
#Context UriInfo uriInfo) {
....
But as long as I registered the SelectableEntityFilteringFeature class, the EntityFilteringFeature class stopped working. I tried to add "fields" parameter to one of the Resource methods, it worked perfectly. But the MyDetailAnnotation was completely useless.
I tried to register it using a DynamicFeature
public class MyDynamicFeature implements DynamicFeature {
#Override
public void configure(ResourceInfo resourceInfo, FeatureContext context) {
if ("MyResource".equals(resourceInfo.getResourceClass().getSimpleName())
&& "getItem".equals(resourceInfo.getResourceMethod().getName())) {
//*** IS THE CORRECT WAY TO BIND A FEATURE TO A METHOD? ***
//
context.register(SelectableEntityFilteringFeature.class);
context.property(SelectableEntityFilteringFeature.QUERY_PARAM_NAME, "fields");
}
}
Now the questions:
1) Why registering both the SelectableEntityFilteringFeature feature breaks the EntityFilteringFeature?
2) What is the correct way to bind a feature to a method with the DynamicFeature interface?
Thanks in advance.
This is my first post to Stack Overflow, I hope it was written complaining the rules.
Short answer: you can't. It appears to be a bug as of 2.25.1 and up to 2.26(that I tested with). https://github.com/jersey/jersey/issues/3523
SelectableEntityFilteringFeature implictily registers EntityFilteringFeature (As mentioned here). So I don't see a need to add this.
Since you need Annotation based filtering, you can exclude registering SelectableEntityFilteringFeature.
You can just do,
// Set entity-filtering scope via configuration.
.property(EntityFilteringFeature.ENTITY_FILTERING_SCOPE, new Annotation[] {MyDetailView.Factory.get()})
// Register the EntityFilteringFeature.
.register(EntityFilteringFeature.class)
// Further configuration of ResourceConfig.
You can refer to this example for usage and this example for registering the filter.
So you can remove SelectableEntityFilteringFeature and try just the above mentioned way to register it.
I have a rest service which returns marker interface and this interface have multiple implementations and don't have any common property in the implementations.
#RequestMapping(value = "/users/{userName}", method = RequestMethod.GET)
public User getUser(#PathVariable("userName") String userName) {
return userService.getUser(userName);
}
User and its implementations.Note : User is marker interface.
public interface User {}
public AdminUser implements User { // some properties & its setters & getters }
public SupportUser implements User { // some properties & its setters & getters }
I use Jackson 1.9.1 to serialize and deserialize.
When I hit above service, I am getting below response
{}
When I debug it, I see user implementation object is prepared and sent back to Jackson for serialization.But jackson is sending empty response to browser.Can anyone suggest how to use serialize when return type is marker interface.
Use #JsonTypeInfo and #JsonSubTypes to deserialization polymorphic types, which maintain sub type information while serializing java object and recreate the exact sub type.
Lets take a example, animal is a Interface and it can be an tiger or a lion, and they both extend the Animal Interface . While deserializing we want to create the exact animal type and demonstrate the use of #JsonTypeInfo and #JsonSubTypes annotations.
#JsonTypeInfo(use=JsonTypeInfo.Id.NAME,
include=JsonTypeInfo.As.PROPERTY,
property="name")
#JsonSubTypes({
#JsonSubTypes.Type(value=Lion.class, name="lion"),
#JsonSubTypes.Type(value=Tiger.class, name="tiger"),
})
public interface Animal {
}
#JsonTypeName("lion")
public class Lion implements Animal {
private String name;
private String roar;
//constructor & setters & getters
}
#JsonTypeName("tiger")
public class Tiger implements Animal {
private String name;
private String purr;
//constructor & setters & getters
}
Main Method :
List<Animal> animal = new ArrayList<Animal>();
animal.add(new Lion("lion", "roar"));
animal.add(new Tiger("tiger", "purr"));
animal.add(new Tiger("tiger", "purrrrrrrrr"));
URL url = JacksonPolymorphicSerialization.class.getClassLoader().getResource("animals.json");
File file = new File(url.getPath());
// de-serailization sub types
new ObjectMapper().writeValue(file, animal);
// serailization animals and its subtype
List<Animal> animals = new ObjectMapper().readValue(file, List.class);
System.out.println(animals);
output : [{name=lion, roar=roar}, {name=tiger, purr=purr}, {name=tiger, purr=purrrrrrrr}]
Hope this helps you understanding serializing and deserializing polymorphic types using Jackson.
You can use #JsonTypeInfo annotation which adds a property to share type information between serializing/deserializing.
Read more here: JsonTypeInfo.html
I am trying to receive this object in my web service from a html page. In the browser opened by eclipse works fine but when i try the same thing in firefox i get the fallowing problem:
Caused by: javax.xml.bind.UnmarshalException: unexpected element (uri:"http://www.w3.org/1999/xhtml", local:"userclient"). Expected elements are <{}userclient>
#XmlRootElement
public class Userclient {
#XmlElement
private String first_name;
#XmlElement
private String last_name;
#XmlElement
private String email;
public Userclient() {
}
//....
}
//Reciving
#PUT
#Consumes("application/xml")
public Response addUser(Userclient user,
#CookieParam("sessionId") String sessionCookie) {
}
//Sending
<script>
RestServlet.addUser({
$entity : userclient
});
</script>
Here are a couple of options for solving your problem based on what your XML looks like:
Option #1 - elementFormDefault="unqualified"
Input XML
If in your XML only the global (top level) elements are namespace qualified:
<ns:userclient xmlns:ns="http://www.w3.org/1999/xhtml">
<first_name>Jane</first_name>
<ns:userclient>
Userclient.java
Then you could just specify the namespace parameter on the #XmlRootElement annotation.
#XmlRootElement(namespace="http://www.w3.org/1999/xhtml"
public class Userclient {
Option #2 - elementFormDefault="qualified"
Input XML
If all the elements are namespace qualified like:
<userclient xmlns="http://www.w3.org/1999/xhtml">
<first_name>Jane</first_name>
<userclient>
package-info.java
You can use the package level #XmlSchema annotation to apply namespace qualification to your model.
#XmlSchema(
namespace = "http://www.w3.org/1999/xhtml",
elementFormDefault = XmlNsForm.QUALIFIED)
package example;
import javax.xml.bind.annotation.XmlNsForm;
import javax.xml.bind.annotation.XmlSchema;
For More Information
Below is a link to an article on my blog that covers more about JAXB and namespace qualification:
http://blog.bdoughan.com/2010/08/jaxb-namespaces.html
Note
You are currently adding more annotations than are necessary. JAXB is configuration by exception so you only need to add annotations where you want the XML representation to differ from the default.
For More Information
Below is a link to an article on my blog that covers more about JAXB's default XML representation:
http://blog.bdoughan.com/2012/07/jaxb-no-annotations-required.html
#XmlRootElement
#XmlAccessorType(XmlAccessType.FIELD)
public class Userclient {
private String first_name;
private String last_name;
private String email;
public Userclient() {
}
//....
}
I'm trying to create form with Vaadin using "Binding form to data" with this class:
public class Job {
private String nom_projet;
private String svn;
private String planning1;
private String planning2;
private String goals;
}
with getters and setters.
When I try this everything works fine:
final Form form = new Form();
Job bean = new Job();
BeanItem<Job> item = new BeanItem<Job>(bean);
form.setItemDataSource(item);
I tried to add a custom field like its described in "Book of Vaadin" so I created this class:
public class MyFieldFactory implements FormFieldFactory {
private static final long serialVersionUID = 1L;
public Field createField(Item item, Object propertyId, Component uiContext) {
Select select = new Select("goals");
select.addItem("compiler:compile");
select.addItem("clean install");
select.addItem("clean");
select.addItem("package");
select.addItem("test");
select.setNewItemsAllowed(true);
return select;
}
}
But when I wanted to add this statement to MyApplication.java:
form.setFieldFactory(new MyFieldFactory());
I got "setFieldFactory" underlined and 3 choices:
() Cast argument 1 to FieldFactory
Change to setFirldFormFactory(...)
Let 'MyFieldFactory' implements 'FieldFactory'
When I click on:
Let 'MyFieldFactory' implements 'FieldFactory'
custom field does not appear in form.
the setFieldFactory method take a FieldFactory as parameter and your MyFieldFactory class implements FormFieldFactory wich is not the same.
In Vaadin javadoc, the setFieldFactory is mark as deprecated and they hint you to use setFormFieldFactory(FormFieldFactory formFieldFactory) instead.
Using this method will solve your problem.
Regards.