Parsing/Unmarshaling query strings which passing arrays as parameters in Java - java

Is there a way to Parse/Unmarshall query strings which passing arrays as parameters in Java into Map or custom class?
URL example:
localhost:8080/app/ws/categories?take=10&skip=10&page=2&pageSize=10&filter[logic]=and&filter[filters][0][field]=company_id&filter[filters][0][operator]=eq&filter[filters][0][value]=1513
I need to parse filter parameter in something like this:
public class Filter {
private String logic;
private List<Filters> filters;
public class Filters {
private String field;
private String operator;
private String value;
}
}
One more point - I'm using Jersey here, maybe it has possibility to Parse/Unmarshall #QueryParam using Jersey's tools?
Anyway any other Java solutions will be OK too.

I would suggest 2 things :
Either you want to perform a GET, then to keep a RESTful approach, I would have an Url like :
localhost:8080/app/ws/categories?take/10/skip/10/page/2/pageSize/10/filter/logic/and/ ...etc
Or POST is acceptable, and I would send JSON payload

We can do it utilizing #BeanParam from JAXRS 2.0 spec
public PageableResponse<PatientBundleType> getPatientBundles(#BeanParam final PageableBeanParam paging)
{
...
}
public class PageableBeanParam
{
public PageableBeanParam(#Context final UriInfo uriInfo)
{
for (Entry<String, List<String>> param : params.entrySet())
{
String key = param.getKey();
String value = param.getValue().iterator().next();
if ("pageSize".equals(key))
{
setPageSize(Integer.valueOf(value));
}
...
}
}
}

Related

Validating input datatype

I am using below DTO class with respective annotations and are working fine also. But when I send a integer value for name/reqID(which is a String datatype) fields, still it is executing without any error/exception. How to avoid it or validate the datatype of incoming fields.
public class RequestDTO {
#NotEmpty(message = "Please provide reqID")
private String reqID;
#NotEmpty(message = "Please provide name")
private String name;
private Map <String, String> unknownProperties;
public AccountDTO(){
this.unknownProperties = new HashMap<String, String>();
}
public AccountDTO(String reqID, String name){
this.reqID= reqID;
this.name = name;
this.unknownProperties = new HashMap<String, String>();
}
#JsonAnySetter
public void add(String key, String value) {
this.unknownProperties.put(key, value);
}
#JsonAnyGetter
public Map <String, String> getUnknownProperties() {
return unknownProperties;
}
//getters and setters
}
working for { "reqID" : 56, "name" : 674 }. Have to check the datatype/reject the request. Any help would be appreciable.
If you're using Spring boot, by default it uses Jackson to parse JSON. There's no configuration option within Jackson to disable this feature
Here you will find interesting approaches to solving this problem:
Disable conversion of scalars to strings when deserializing with Jackson
You can disable MapperFeature ALLOW_COERCION_OF_SCALARS which is enabled by default.
Then conversions from JSON String are not allowed.
Doc Details here
public static final MapperFeature ALLOW_COERCION_OF_SCALARS
When feature is disabled, only strictly compatible input may be bound:
numbers for numbers, boolean values for booleans. When feature is
enabled, conversions from JSON String are allowed, as long as textual
value matches (for example, String "true" is allowed as equivalent of
JSON boolean token true; or String "1.0" for double).
Or create a custom json deserializer for string overriding default serializer JsonDeserializer<String>.
You could validate the input you are getting. But this is not specific to your DTO so if you have some sort of Utilities class with static methods (think about having one if you don't) it's better if you add it there and grab it for any DTO that might need this validation.
The validation method would look something like this:
public static boolean isNumber(String in) {
try{
Integer.parseInt(in);
// log something useful here
return true;
} catch(NumberFormatException e) {
return false;
}
}
You could then use this method throw your own exception. Then handle that the way you'd need:
if (Utilities.isNumber(reqID)){
throw new IllegalArgumentException("Meaningful Exception Message here");
}
I hope it helps! :)
Spring boot allows regular expression checking using #Patter annotation. So just add the following
#Pattern(regexp="[a-zA-Z]")
#NotEmpty(message = "Please provide name")
private String name;

Jersey to filter and return a subset of representation list

Using Jersey 2.16, I'm looking to return a subset of a list by passing a boolean query parameter that will match a boolean field in a representation list.
For example, let's say I've got an apple resource like so:
#GET
#Path("apple/list")
public Response getAppleList(#DefaultValue("false") #QueryParam("isGreen") final boolean isGreen) {
return appleService.getAppleList();
}
And my apple representation looks like this:
public class AppleRepresentation {
private int id;
private String colour;
private String country;
private String isGreen;
}
Is there a built-in Jersey filtering mechanism that will filter my List<AppleRepresentation> and return only green apples?
So far I've looked into Jersey entity filtering. From what I've seen there are ways to either filter out an entire list or fields with SelectableEntityFilteringFeature.
Unfortunately, I can't see an easy way to return only a subset of a list where a field = value.
Did you try the native stream filtering method of Java 8?
appleService.getAppleList().stream().filter(a -> a.isGreen);
Considering isGreen is a boolean…
(Didn't test it, though)

How to get values by name with JAX-RS(JSR339)

Colleagues in my office are developping a web system with JAX-RS(JSR339).
I need to get values by name(string) and I asked them to. But they have few idea.
I'm quite new to JAX-RS and googled it and I learned that
JAX-RS injects values to variables by annotations like
#Path("/sample")
public interface SampleResource {
#GET
#Path("/hello/{message}")
String sayHello(#PathParam("message") String message);
}
However I want to get values by name at runtime like
#Path("/sample")
public interface SampleResource {
String name = "message"; // dynamic value
#GET
#Path("/hello/{" + name + "}")
String sayHello(#PathParam(name) String message);
}
Perhaps this is a wrong code. My question is how to get values by name like the example above.
(I'm afraid the sample codes aren't correct ones but I hope you grasp my idea and concerns. Thanks.)
Try something like this.
Example of the bean which will be used as #BeanParam
public class MyBeanParam {
#PathParam("p")
private String pathParam;.
public String getPathParam() {
return pathParam;
}
}
Injection of MyBeanParam as a method parameter:
#GET
String sayHello(#BeanParam MyBeanParam beanParam, String entity){
final String pathParam = beanParam.getPathParam(); // contains injected path parameter "p"
...
}
OR
You can use UriInfo to get QueryParam. For example application see this

Cloud Endpoints: Arrays or collections of entity types are not allowed

Why is there this limitation in Google Cloud Endpoints:
Arrays or collections of entity types are not allowed.
For an API with method:
#ApiMethod(name = "getCollection", path = "getCollection", httpMethod = HttpMethod.POST)
public ArrayList<MyObject> getCollection(List<MyObject> pMyObjects) {
And what's the best way to get around this? Thanks!
I think the reason it's not supported is because the named parameters in the method signature end up being URL query parameters, and they don't want to pollute that with long lists of items. Furthermore, they only support a single object of an Entity type in the signature, because this automatically becomes the "request body". You can read about it here in the docs.
As for working around it, you create a container entity object for the "request body". The nice side effect of this is that the APIs Explorer will expand the pieces of your entity object out in the GUI and help you do the JSON correctly.
Here's an example that adds a Map named "patchFieldOps" for implementing partial update. You can put as many fields into your Entity object as you like. I think if you embed more user-defined types they will also need to have the #Entity annotation.
#Entity
public class EndpointUpdateRequestBody {
// Since Google Cloud Endpoints doesn't support HTTP PATCH, we are overloading
// HTTP PUT to do something similar.
private Map<String, String> patchFieldsOps;
public EndpointUpdateRequestBody() {
patchFieldsOps = new HashMap<String, String>();
}
public EndpointUpdateRequestBody(Map<String, String> patchFieldsOps) {
this.patchFieldsOps = patchFieldsOps;
}
public Map<String, String> getPatchFieldsOps() {
return patchFieldsOps;
}
public void setPatchFieldsOps(Map<String, String> patchFieldsOps) {
this.patchFieldsOps = patchFieldsOps;
}
}
...
#ApiMethod(
name = "stuff.update",
path = "stuff/{id}",
httpMethod = ApiMethod.HttpMethod.PUT
)
public Group update(
User apiUser,
#Named("id") String id,
#Nullable #Named("name") String name,
#Nullable #Named("description") String description,
EndpointUpdateRequestBody requestBody)
throws OAuthRequestException, InternalServerErrorException, NotFoundException,
BadRequestException, UnauthorizedException, ConflictException {

How to convert HTTP Request Body into JSON Object in Java

I am trying find a Java lib/api that will allow me to turn the contents of a HTTP Request POST body into a JSON object.
Ideally I would like to use a Apache Sling library (as they are exposed in my container naturally).
The closest I've found it: org.apache.sling.commons.json.http which converts the header to JSON.
HTTP Post bodies are in the format; key1=value1&key2=value2&..&keyn=valueN so I assume there is something out there, but I havent been able to find it.
I may just have to use a custom JSONTokener (org.apache.sling.commons.json.JSONTokener) to do this if something doesn't already exist. Thoughts?
Thanks
Assuming you're using an HttpServlet and a JSON library like json-simple you could do something like this:
public JSONObject requestParamsToJSON(ServletRequest req) {
JSONObject jsonObj = new JSONObject();
Map<String,String[]> params = req.getParameterMap();
for (Map.Entry<String,String[]> entry : params.entrySet()) {
String v[] = entry.getValue();
Object o = (v.length == 1) ? v[0] : v;
jsonObj.put(entry.getKey(), o);
}
return jsonObj;
}
With example usage:
public void doPost(HttpServletRequest req, HttpServletResponse res) {
JSONObject jsonObj = requestParamsToJSON(req);
// Now "jsonObj" is populated with the request parameters.
// e.g. {"key1":"value1", "key2":["value2a", "value2b"], ...}
}
Jackson is also a good option - its used extensively in Spring. Here is the tutorial: http://wiki.fasterxml.com/JacksonInFiveMinutes
I recommend trying Apache Commons Beanutils.
ServeltRequest request;
Map map = request.getParameterMap();
MyObject object = new MyObject();
BeanUtils.populate(object, map);
String json = object.toJSON() //using any JSON library
Sorry on making this an own answer but obviously my reputation doesn't allow me to simply add a comment to the answer How to convert HTTP Request Body into JSON Object in Java of maerics.
I would also iterate over the request params but instead of using an arbitrary json library use the JSONObject that is provided by sling. http://sling.apache.org/apidocs/sling6/org/apache/sling/commons/json/JSONObject.html
import org.json.JSONObject;
JSONObject json = new JSONObject(request.getParameterMap())
Use Gson. With this you can create class with private variables which represent the data you want : for example.
meta:{
name:"Example"
firstname:"Example2"
}
data:[
{
title:"ecaetra"
description:"qwerty"
}
...
]
Json Object could be retrieve like this :
public class RetrieveData {
private Meta meta;
private List<Data> data;
public Meta getMeta(){
return meta;
}
public List<Data> getData(){
return data;
}
}
public class Meta {
private String name;
private String firstname;
public String getName(){
return name;
}
public String getFirstName(){
return firstname;
}
}
public class Data {
private String title;
private String description;
public String getTitle(){
return title;
}
public String getDescription(){
return description;
}
}
And your instruction are simple. Content is the content of your Page, you can retrieve it with Asynctask.
Object o = new Gson().fromJson(Content, RetrieveData.class);
data = (RetrieveData)o;
// Get Meta
data.getName(); // Example
data.getFirstName(); // Example2
// Get Data
data.get(0).getTitle(); // position 0 : ecaetra
data.get(0).getDescription(); // position 0 : qwerty

Categories