How to handle an empty-string property name in Java - java

I need to use a response from a rest service returning JSON. However, one of the fields in the json response is the empty string. So, basically this:
{"wut":
{
"foo":"fooval",
"": "srsly"
}
}
So, I need to somehow translate this into a java class, as below:
#JsonIgnoreProperties(ignoreUnknown=true)
public class wut
{
#JsonProperty
private String foo;
#JsonProperty
private String <empty string???>;
//etc...
}
As you might expect, I don't have enough control over the endpoint to be able to give the property a name. Is there a way to handle this?
I'm using RestTemplate from spring to make the call, if that matters at all.

Related

How to extract the url from application.properties?

I have this application.properties:
url.up=${url:http://localhost:8080/upload}
And I want to extract the url "http://localhost:8080/upload". How can I extract it?
I tried something like this, but the url is null:
String url = config.getPropertyValue("url");
Where getPropertyValue:
public String getPropertyValue(String propertyKey) {
return properties.getProperty(propertyKey);
}
U can use #Value in your class
in your property file U can define
url.up=http://localhost:8080/upload
In Your class
#Value("${url.up}")
private String url;
then U can access the value using variable url
Unfortunately I do not know what class the config object is instatiated from which makes it hard to understand what the properties.getProperty() method call is doing. Therefore, I'll give you a a more general answer. As you are using Spring, you basically have two very elegant solutions to retrieve data from your application property files. If you just need a single value (as in your example the url.up field), then you would typically directly inject that value into the class that needs this data as in the following short Kotlin snippet (in java this would be very similar, just look up the #Value annotation on the internet).
#Component
class PropertyPrinter(
#Value("\${url.up}") private val url: String
) {
#PostConstruct
fun postConstruct() {
println("URL is: $url")
}
}
The other way would be to create a dedicated config class that hold a bunch logically connected fields and add the #ConfigurationProperties annotation. See here for a more in depth explanation.
You should use #Value annotation. For example:
#Value("${url}")
private String url;
The url variable holds http://localhost:8080/upload.
You should use #Value or appContext:
https://stackoverflow.com/a/29744955/21233858

Java method Overloading with REST - org.codehaus.jackson.map.JsonMappingException

I have a REST service that has a POST endpoint. This POST endpoint needs to receive an object (TravelRequisitionFormDTO) as part of its body:
#POST
#Path("/request")
#ApiOperation(value="Request a trip. Submit the trip request.")
#ApiResponses({
#ApiResponse(code=200, message="Success"),
#ApiResponse(code=404, message="Not Found")
})
#Produces({ MediaType.APPLICATION_JSON })
public Response getSubmitTrip(#HeaderParam("Authorization") String token, #ApiParam(required = true) TravelRequisitionFormDTO travelRequisitionFormDTO, #Context HttpServletRequest request) {
...
}
So when I call the endpoint, I get the following error:
<p><b>message</b> <u>org.codehaus.jackson.map.JsonMappingException: Conflicting setter definitions for property
"contactMethods": utility.dataobjects.ContactObject#setContactMethods(1 params) vs
utility.dataobjects.ContactObject#setContactMethods(1 params)</u></p>
<p><b>description</b> <u>The request sent by the client was syntactically incorrect
(org.codehaus.jackson.map.JsonMappingException: Conflicting setter definitions for property
"contactMethods": utility.dataobjects.ContactObject#setContactMethods(1 params) vs
utility.dataobjects.ContactObject#setContactMethods(1 params)).</u></p>
The reason for the error is because the TravelRequisitionFormDTO has a member variable (called ContactObject) that has two methods that are overloaded. So when it tries to convert the JSON body to JAVA, I guess it does not know which overloaded method to use. I think it sees it as ambiguous.
public void setContactMethods(ArrayList list)
and
public void setContactMethods(String[] list)
I don't want to change ContactObject if possible, because it is used in a number of other places.
Question
Is there any way I can resolve this? i.e. so that the JSON body can be converted successfuly into the Java object?
you can keep single property accepting List. and your Contractobject can consume both Array & List.
You could annotate one setter with Jackson #JsonSetter annotation:
#JsonSetter
public void setContactMethods(ArrayList list)
Make sure that you use right package. In your case it would be org.codehaus.jackson.annotate.JsonSetter like you can see in the error message. It might happen that you have also com.fasterxml.jackson.annotation.JsonSetter in the classpath so you have to be careful not to mix it.
Alternatively you can use #JsonProperty instead.

How to set get query parameter name in spring #RestController Servlet?

I have a simple #RestController and want to create a request object that holds any values from a GET query.
Moreover I'd like to use variable names being different from the get query parameter names.
#RestController
public class MyServlet {
#RequestMapping(value = "/start")
public String start(#Valid MyRequest req) {
Logger.log("IN");
return req.getTest();
}
}
public class MyRequest {
#XmlElement(name = "asd")
private String test;
//getter, setter
}
Request: localhost:8080/start?asd=imhere
Result: I'm seing the log statement IN, so the servlet works.
BUT req Parameter is null. Why?
It works if I send the following url: localhost:8080/start?test=imhere
So the servlet works, but not the parameter renaming.
Spring will try to build your MyRequest object using setters or reflecting into private variables, therefore the test variable will only be populated when you send a test parameter.
From the documentation (#RequestMapping - Supported method argument types):
Command or form objects to bind request parameters to bean properties
(via setters) or directly to fields...
Edit - If you want to change names you'll likely need a Converter. See:
docs
mvc example

How to deal with dozens of different JSON responses?

Throughout my app, I request JSON data from my web server and the response is almost always in a different.
For example, one response might look like this:
{"success":true,"data":{"token_id":"pPt9AKl0Cg","token_key":"8ax224sFrJZZkStAQuER"}}
While another might look like this:
{"success":true,"data":{"user_id":"20","username":"Bob"}}
And another might look like this:
{"success":true,"data":{"user_id":"20","stats":{"followers":"500","following":"12"}}}
Previously, I created a model class (Java) for each different response type. For example, for the first response above, my model class might look like this:
public class MyResponseModel {
private boolean success;
private DataModel data;
public static class DataModel {
private String token_id;
private String token_key;
}
...
}
Is this really the best way of doing this? Because if I do this for the dozen+ responses I get across my app, I'll end up with a dozen+ different model classes, one for each different response.
Are there alternatives to parsing JSON?
Thanks.
You will need one DTO or model class for each type of response. The static typing is required to serialize/deserialize from/to json. You can use generics to wrap the response. Refactoring your code this will be something like:
public class MyResponseModel <T> {
private boolean success;
private T data;
}
public class DataModel {
private String token_id;
private String token_key;
}
Then your code can return MyResponseModel<DataModel> object for this scenario.
If you really want to use one class for every type of response you will need to represent all your response as key value pairs and then you can have one class containing a Map. I will not recommend that approach and would prefer to have one class for each type of response.
Check out https://github.com/jayway/JsonPath , it`s only in the Java world where the default solution is to serialize/deserialize.

Bean with generic field that is not always used

This is a curious situation: I have a bean like this that store some information and I need generics, because the field "data" can contain different types of data.
public class Request<T> {
private String name;
private Integer code;
private T data;
/* Getter and setters */
}
The fact is that "data" is not always used and sometimes it can be null. And if I want to avoid raw types I have to define a type anyway, like this:
Request<Object> req = ....
Is there a better way of doing that, where I can both 1) Avoid raw types 2) Have a generic data field in my request objects ???
If you don't mind the request type, use Request<?> in your declaration.
If the request is empty (meaning there is no type, which can be set as data), declare it as Request<Void>
You could always use the Void type, e.g.
Request<Void> req = ...
or a wildcard:
Request<?> req = ...
Maybe you should consider to change object hierarhy. If you dont use data in some cases, maybe you should have two objects:
class Request {
private String name;
private Integer code;
/* Getter and setters */
}
class DataRequest<T> extends Request {
private T data;
/* Getter and setters */
}
and use:
Request req1 = new Request();
Request req2 = new DataRequest<String>();
Maybe you should think in a different way: In your case a Request not always has associated data. Modelling this with null-values is a bad decision, because you have to check for this every time you want to use your data. At some point you want to handle Request without data in a different way then Request with data.
Maybe you should make your Request to an interface containing Methods like getName() and getCode() and create two concrete classes RequestWithData<T> and RequestWithoutData implementing this interface. Then you can check on creation of an RequestWithData<T>-instance, if a non-null data is provided. Furthermore, you can express in your method signature that you require a Request with data or without data. This leads to a more clean design and avoids your problem.
Use the new 'Optional' type in Java 8. It was made specifically for cases like these. If you cannot, for whatever reason, use Java 8 yet, the Google Guava library also implements that type. Check this example : https://gist.github.com/9833966

Categories

Resources