Get Json object from Itis with spring boot - json

I try to get a Json object from Itis Webservice (https://www.itis.gov/ITISWebService/jsonservice/getHierarchyUpFromTSN?tsn=164282).
I use the following class to store the Json object:
public class Genus {
#JsonProperty("tsn")
private int tsn;
#JsonProperty("taxonName")
private String taxonName;
public Genus() {
super();
}
public int getTsn() {
return tsn;
}
public void setTsn(int tsn) {
this.tsn = tsn;
}
public String getCombinedName() {
return taxonName;
}
public void setCombinedName(String taxonName) {
this.taxonName = taxonName;
}
#Override
public String toString() {
return "Genus [tsn=" + tsn + ", taxonName=" + taxonName + "]";
}
}
My main method:
public static void main(String[] args) {
RestTemplate restTemplate = new RestTemplate();
Genus quote = restTemplate.getForObject("https://www.itis.gov/ITISWebService/jsonservice/getHierarchyUpFromTSN?tsn=164282", Genus.class);
System.out.println(quote.toString());
}
As result I get the following exception:
Exception in thread "main"
org.springframework.web.client.RestClientException: Could not extract
response: no suitable HttpMessageConverter found for response type
[class de.aquaristikguru.taxonomy.itisObjects.Genus] and content type
[text/json;charset=ISO-8859-1
How can I fixed it?

Related

Error in parsing Json File to java object using gson parser

I am trying to parse array of json objects using gson library and I am unable to parse it because of json syntax exception. I am passing the json filepath as argument to method jsonparser.
heres the example code below that i have trouble parsing.
test.json - consists of array of objects
{
"EventRecords": [
{
"eventVersion": "2.0",
"eventSource": "aws:s3",
"awsRegion": "us-east-1",
"eventTime": "2018-05-10T17:10:01.420Z",
"eventName": "ObjectCreated:Put"
}
]
}
GsonParser.java:
public class GsonParser {
public void jsonEncoder(String filePath)
{
Gson gson = new Gson();
Type listType = new TypeToken<List<Record>>(){}.getType();
BufferedReader bufferedReader = new BufferedReader(new FileReader(filePath));
List<Record> records = gson.fromJson(bufferedReader, listType);
System.out.println("\n\nEventRecords\n\n" + records.toString());
}
public static void main(String[] args) throws IOException {
GsonParser obj= new GsonParser();
File f = new File("/Users/test/Desktop/test.json");
obj.jsonEncoder(f.getAbsolutePath());
}
}
Record.java:
public class Record {
String eventVersion;
String eventSource;
String awsRegion;
String eventTime;
String eventName;
public String getEventVersion() {
return eventVersion;
}
public void setEventVersion(String eventVersion) {
this.eventVersion = eventVersion;
}
public String getEventSource() {
return eventSource;
}
public void setEventSource(String eventSource) {
this.eventSource = eventSource;
}
public String getAwsRegion() {
return awsRegion;
}
public void setAwsRegion(String awsRegion) {
this.awsRegion = awsRegion;
}
public String getEventTime() {
return eventTime;
}
public void setEventTime(String eventTime) {
this.eventTime = eventTime;
}
public String getEventName() {
return eventName;
}
public void setEventName(String eventName) {
this.eventName = eventName;
}
#Override
public String toString () {
return ToStringBuilder.reflectionToString(this,ToStringStyle.MULTI_LINE_STYLE);
}
}
Error:
Exception in thread "main" com.google.gson.JsonSyntaxException: java.lang.IllegalStateException: Expected BEGIN_ARRAY but was BEGIN_OBJECT at line 1 column 2 path $
You have object in your JSON and EventRecord is array inside that object.
Add class say EventRecords
public class EventRecords{
private List<Record> eventRecords = new ArrayList<Record>();
public List<Record> getEventRecords() {
return this.eventRecords;
}
public void setEventRecords(List<Record> records) {
this.eventRecords= records;
}
}
And change your deserialization code as
EventRecords eventRecords = gson.fromJson(bufferedReader, listType);
And to fetch the ArrayList change
List<Record> records = eventRecords.getEventRecords();

Unable to get through CXF with JSON

I am trying to build a CXF RESTFul service with JSON as input and output. I am using JAXRSServerFactoryBean to boot my service. When I try to hit the URL from a client program, I am getting the following exception. My program is very simple and attached the same at the bottom.
Please help.
May 19, 2015 11:03:30 PM org.apache.cxf.jaxrs.provider.AbstractJAXBProvider handleExceptionStart
WARNING: javax.xml.stream.XMLStreamException: ParseError at [row,col]:[0,0]
Message: A JSONObject text must begin with '{' at character 0 of
at org.codehaus.jettison.mapped.MappedXMLInputFactory.createXMLStreamReader(MappedXMLInputFactory.java:51)
at org.codehaus.jettison.AbstractXMLInputFactory.createXMLStreamReader(AbstractXMLInputFactory.java:116)
at org.apache.cxf.jaxrs.provider.json.utils.JSONUtils.createStreamReader(JSONUtils.java:162)
at org.apache.cxf.jaxrs.provider.json.JSONProvider.createReader(JSONProvider.java:290)
at org.apache.cxf.jaxrs.provider.json.JSONProvider.createReader(JSONProvider.java:280)
at org.apache.cxf.jaxrs.provider.json.JSONProvider.readFrom(JSONProvider.java:233)
at org.apache.cxf.jaxrs.utils.JAXRSUtils.readFromMessageBodyReader(JAXRSUtils.java:1337)
at org.apache.cxf.jaxrs.utils.JAXRSUtils.readFromMessageBody(JAXRSUtils.java:1288)
at org.apache.cxf.jaxrs.utils.JAXRSUtils.processParameter(JAXRSUtils.java:824)
at org.apache.cxf.jaxrs.utils.JAXRSUtils.processParameters(JAXRSUtils.java:787)
at org.apache.cxf.jaxrs.interceptor.JAXRSInInterceptor.processRequest(JAXRSInInterceptor.java:212)
at org.apache.cxf.jaxrs.interceptor.JAXRSInInterceptor.handleMessage(JAXRSInInterceptor.java:77)
at org.apache.cxf.phase.PhaseInterceptorChain.doIntercept(PhaseInterceptorChain.java:307)
May 19, 2015 11:03:30 PM org.apache.cxf.jaxrs.impl.WebApplicationExceptionMapper toResponse
WARNING: javax.ws.rs.BadRequestException: HTTP 400 Bad Request
at org.apache.cxf.jaxrs.utils.SpecExceptions.toBadRequestException(SpecExceptions.java:84)
at org.apache.cxf.jaxrs.utils.ExceptionUtils.toBadRequestException(ExceptionUtils.java:114)
at org.apache.cxf.jaxrs.provider.AbstractJAXBProvider.handleExceptionEnd(AbstractJAXBProvider.java:705)
at org.apache.cxf.jaxrs.provider.AbstractJAXBProvider.handleXMLStreamException(AbstractJAXBProvider.java:734)
at org.apache.cxf.jaxrs.provider.json.JSONProvider.readFrom(JSONProvider.java:261)
at org.apache.cxf.jaxrs.utils.JAXRSUtils.readFromMessageBodyReader(JAXRSUtils.java:1337)
at org.apache.cxf.jaxrs.utils.JAXRSUtils.readFromMessageBody(JAXRSUtils.java:1288)
at org.apache.cxf.jaxrs.utils.JAXRSUtils.processParameter(JAXRSUtils.java:824)
at org.apache.cxf.jaxrs.utils.JAXRSUtils.processParameters(JAXRSUtils.java:787)
at org.apache.cxf.jaxrs.interceptor.JAXRSInInterceptor.processRequest(JAXRSInInterceptor.java:212)
at org.apache.cxf.jaxrs.interceptor.JAXRSInInterceptor.handleMessage(JAXRSInInterceptor.java:77)
at org.apache.cxf.phase.PhaseInterceptorChain.doIntercept(PhaseInterceptorChain.java:307)
at org.apache.cxf.transport.ChainInitiationObserver.onMessage(ChainInitiationObserver.java:121)
at org.apache.cxf.transport.http.AbstractHTTPDestination.invoke(AbstractHTTPDestination.java:251)
at org.apache.cxf.transport.http_jetty.JettyHTTPDestination.doService(JettyHTTPDestination.java:234)
at org.apache.cxf.transport.http_jetty.JettyHTTPHandler.handle(JettyHTTPHandler.java:70)
at org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:1129)
at org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:1065)
at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:141)
at org.eclipse.jetty.server.handler.ContextHandlerCollection.handle(ContextHandlerCollection.java:215)
at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:97)
Caused by: javax.xml.stream.XMLStreamException: ParseError at [row,col]:[0,0]
Message: A JSONObject text must begin with '{' at character 0 of
at org.codehaus.jettison.mapped.MappedXMLInputFactory.createXMLStreamReader(MappedXMLInputFactory.java:51)
at org.codehaus.jettison.AbstractXMLInputFactory.createXMLStreamReader(AbstractXMLInputFactory.java:116)
at org.apache.cxf.jaxrs.provider.json.utils.JSONUtils.createStreamReader(JSONUtils.java:162)
at org.apache.cxf.jaxrs.provider.json.JSONProvider.createReader(JSONProvider.java:290)
RestFulServiceStarter
public class RestFulServiceStarter {
public static void main(String[] args) {
JAXRSServerFactoryBean sf = new JAXRSServerFactoryBean();
sf.setResourceClasses(ProfileService.class);
sf.setResourceProvider(ProfileService.class,
new SingletonResourceProvider(new ProfileServiceImpl()));
sf.setAddress("http://localhost:9999/");
Server server = sf.create();
}
}
ProfileService
#Path("/profile/")
public interface ProfileService {
#GET
#Path("/static/")
#Consumes({ MediaType.APPLICATION_JSON })
#Produces({ MediaType.APPLICATION_JSON })
public Response getStaticProfiles(ProfileRequest pr);
}
ProfileServiceImpl
public class ProfileServiceImpl implements ProfileService {
public Response getStaticProfiles(ProfileRequest pr) {
return Response.status(200).entity(pr).build();
}
}
ProfileRequest
#XmlRootElement ( name = "profile" )
public class ProfileRequest {
private String name="";
private String country="";
private String region="";
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getCountry() {
return country;
}
public void setCountry(String country) {
this.country = country;
}
public String getRegion() {
return region;
}
public void setRegion(String region) {
this.region = region;
}
}
Your interface method is annotated with a #GET method, yet it also has an entity parameter (ProfileRequest). Try #POST.

How to produce error response in json

Am writing a Restful Webservice Impl, where i consume and produce response in JSON format by annotating #Produces("application/json"). Am producing JSON response as well. Here am handling exception with a class where it has error code and error message. When am getting exception it is not produced in application/json format. I used ExceptionMapper to find a solution but it is `text/plain format.
snippet
public Class Confiuration{
#Path("getData")
#Consumes("application/json")
#Produces("application/json")
public JSONGetDataResponseVo getData(GetDataRequestVo datarequestVO)
throws FaultResponse {
JSONGetDataResponseVo response=new JSONGetDataResponseVo ();
DataServiceValidator.validateGetConfigurationAndDataRequest(datarequestVO);
....
....
}catch(ApplicationException applicationException){
throw new FaultResponse(applicationException,locale);
}
}
FaultResponseMapper
#Provider
public class FaultResponseMapper implements ExceptionMapper<FaultResponse> {
#Context
private HttpHeaders headers;
public Response toResponse(FaultResponse faultResponse) {
return Response.status(Response.Status.INTERNAL_SERVER_ERROR)
.entity(faultResponse).type(MediaType.APPLICATION_JSON).build();
}
}
Application Exception
public abstract class ApplicationException extends Exception{
private java.lang.String errorCode;
public ApplicationException(String errorCode, String message) {
super(message);
this.errorCode = errorCode;
}
public ApplicationException(String message) {
super(message);
}
public java.lang.String getErrorCode() {
return this.errorCode;
}
public abstract String getLocaleMessage(Locale locale);
}
FaultResponse
public class FaultResponse extends WebApplicationException {
private String errorCode;
private String errorMessage;
private String localErrorMessage;
public FaultResponse(String errorCode, String errorMessage,
String localErrorMessage) {
this.errorCode = errorCode;
this.errorMessage = errorMessage;
this.localErrorMessage = localErrorMessage;
}
public FaultResponse(ApplicationException applicationException,
Locale locale) {
this.errorCode = applicationException.getErrorCode();
this.errorMessage = applicationException.getMessage();
if (locale != null
&& applicationException.getLocaleMessage(locale) != null) {
this.localErrorMessage = applicationException
.getLocaleMessage(locale);
} else {
this.localErrorMessage = applicationException.getMessage();
}
}
}
So here how can i produce my faultResponse in JSON format.
This has to do with the fact that you are returning an exception as a response. I would
Make an exception mapper for ApplicationException.
Refactor FaultResponse to not extend and exception. Just create it in the mapper.
In order to see the response, you will need to send a status other than No Content. You can't have a body in it. Send somethng like Bad Request.
You can just declare the resource method as throws ApplicationException. You don't need to catch it and rethrow.
I've made these changes, and it works fine.
UPDATE: with complete test
Added getters (required for marshalling) to FaultResponse and remove the exception extension
public class FaultResponse {
...
public String getErrorCode() { return errorCode; }
public String getErrorMessage() { return errorMessage; }
public String getLocalErrorMessage() { return localErrorMessage; }
...
}
Created a Service for testing and ApplicationException implementation
public class ApplicationExceptionImpl extends ApplicationException {
public ApplicationExceptionImpl(){
this("400", "Bad Request");
}
public ApplicationExceptionImpl(String errorCode, String message) {
super(errorCode, message);
}
#Override
public String getLocaleMessage(Locale locale) {
return "Bad Request";
}
}
public class FaultService {
public void doSomething() throws ApplicationException {
throw new ApplicationExceptionImpl();
}
}
Resource class
#Path("fault")
public class FaultResource {
FaultService service = new FaultService();
#GET
public Response getException() throws ApplicationException {
service.doSomething();
return Response.ok("Cool").build();
}
}
ExceptionMapper
#Provider
public class ApplicationExceptionMapper implements ExceptionMapper<ApplicationException> {
#Override
public Response toResponse(ApplicationException exception) {
FaultResponse response = new FaultResponse(exception, Locale.ENGLISH);
return Response.status(Response.Status.BAD_REQUEST)
.entity(response).type(MediaType.APPLICATION_JSON).build();
}
}
ApplicationException class is left the same
curl -v http://localhost:8080/api/fault
{"errorCode":"400","errorMessage":"Bad Request","localErrorMessage":"Bad Request"}
If after this you are still not seeing JSON, it's possible you do not have a provider configured. If this is the case, please show your application configuration, along with your project dependencies.

Simple way to strip outer array of responses in gson

I'm working with an api (Phillips Hue) that wraps all of it's json responses in an array with one entry (the content).
Example:
[{
"error": {
"type": 5,
"address": "/",
"description": "invalid/missing parameters in body"
}
}]
I usually write standard POJO's parsed by GSON to handle responses but since the response is not a json object I'm a bit stumped on the best way to deal with this. I didn't really want every object to actually be an array that I have to call .get(0) on.
Example of the POJO if it was a JSON obj and NOT wrapped in an array.
public class DeviceUserResponse {
private DeviceUser success;
private Error error;
public DeviceUser getSuccess() {
return success;
}
public Error getError() {
return error;
}
public static class Error {
private int type;
private String address;
private String description;
public int getType() {
return type;
}
public String getAddress() {
return address;
}
public String getDescription() {
return description;
}
#Override
public String toString() {
return "Type: " + this.type
+ " Address: " + this.address
+ " Description: " + this.description;
}
}
}
What I have to do right now:
ArrayList<DeviceUserResponse> response.get(0).getError();
Is there a way that I can strip this array for every response or am I just going to have to do a .get(0) in my POJO's and just not expose it?
I think you've to go with custom deserialization in order to "strip out" the array.
Here a possible solution.
An adapter for your response POJO:
public class DeviceUserResponseAdapter extends TypeAdapter<DeviceUserResponse> {
protected TypeAdapter<DeviceUserResponse> defaultAdapter;
public DeviceUserResponseAdapter(TypeAdapter<DeviceUserResponse> defaultAdapter) {
this.defaultAdapter = defaultAdapter;
}
#Override
public void write(JsonWriter out, DeviceUserResponse value) throws IOException {
defaultAdapter.write(out, value);
}
#Override
public DeviceUserResponse read(JsonReader in) throws IOException {
in.beginArray();
assert(in.hasNext());
DeviceUserResponse response = defaultAdapter.read(in);
in.endArray();
return response;
}
}
A factory for your adapter:
public class DeviceUserResponseAdapterFactory implements TypeAdapterFactory {
#Override
#SuppressWarnings("unchecked")
public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) {
if (type.getRawType()!=DeviceUserResponse.class) return null;
TypeAdapter<DeviceUserResponse> defaultAdapter = (TypeAdapter<DeviceUserResponse>) gson.getDelegateAdapter(this, type);
return (TypeAdapter<T>) new DeviceUserResponseAdapter(defaultAdapter);
}
}
Then you've to register and user it:
DeviceUserResponseAdapterFactory adapterFactory = new DeviceUserResponseAdapterFactory();
GsonBuilder gsonBuilder = new GsonBuilder();
Gson gson = gsonBuilder.registerTypeAdapterFactory(adapterFactory).create();
DeviceUserResponse response = gson.fromJson(json, DeviceUserResponse.class);
System.out.println(response.getError());
This solution will not work if you have the DeviceUserResponse inside other complex JSON object. I that case the adapter will try to find an array and will terminate with an error.
Another solution is to parse it as array and then in your "communication" layer you get only the first element. This will preserve the GSon deserialization.
In the comment you're asking for a more generic solution, here one:
The adapter:
public class ResponseAdapter<T> extends TypeAdapter<T> {
protected TypeAdapter<T> defaultAdapter;
public ResponseAdapter(TypeAdapter<T> defaultAdapter) {
this.defaultAdapter = defaultAdapter;
}
#Override
public void write(JsonWriter out, T value) throws IOException {
defaultAdapter.write(out, value);
}
#Override
public T read(JsonReader in) throws IOException {
in.beginArray();
assert(in.hasNext());
T response = defaultAdapter.read(in);
in.endArray();
return response;
}
}
The factory:
public class ResponseAdapterFactory implements TypeAdapterFactory {
#Override
public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) {
if ((type.getRawType().getSuperclass() != Response.class)) return null;
TypeAdapter<T> defaultAdapter = (TypeAdapter<T>) gson.getDelegateAdapter(this, type);
return (TypeAdapter<T>) new ResponseAdapter<T>(defaultAdapter);
}
}
Where Response.class is your super class from which all the service responses inherit.
The first solution advices are still valid.

Java unmarshilling JSON data containg abstract type

We are using Jersey/Jackson to unmarshall JSON data to java DTOs. One of my DTO is an abstract class, and i would like to unmarshall the JSON data to one of his extended DTO. For example, assuming i have these DTOs :
public abstract class AnimalDTO{}
public class DogDTO extends AnimalDTO{}
public class CatDTO extends AnimalDTO{}
I would like to unmarshall this JSON data:
{Zoo: {Animals:[{"type"="DogDTO", "code"="001", "name"="chihuahua"}, {"type"="CatDTO", "code"="002", "name"="felix"}]}}
As "type" would give the type of DTO i would like to unmarshall to. But it seems that this property isn't considered. Is there something I missed, or mistook in the JSON syntax?
Thanks.
In your case you should use #JsonTypeInfo annotation.
For more information, please see below links:
JacksonFAQ.
Jackson 1.5: Polymorphic Type Handling, first steps.
Using above links I have created a simple example which serialize POJO objects with class names:
import java.io.StringWriter;
import java.util.Arrays;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.databind.ObjectMapper;
public class JacksonProgram {
public static void main(String[] args) throws Exception {
DogDTO dog = new DogDTO();
dog.setCode("001");
dog.setName("chihuahua");
CatDTO cat = new CatDTO();
cat.setCode("002");
cat.setName("felix");
Zoo zoo = new Zoo();
zoo.setAnimals(new AnimalDTO[] { dog, cat });
Data data = new Data();
data.setZoo(zoo);
ObjectMapper objectMapper = new ObjectMapper();
StringWriter writer = new StringWriter();
objectMapper.writeValue(writer, data);
System.out.println(writer);
}
}
#JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "type")
abstract class AnimalDTO {
private String code;
private String name;
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
#Override
public String toString() {
return "AnimalDTO [code=" + code + ", name=" + name + "]";
}
}
class DogDTO extends AnimalDTO {
}
class CatDTO extends AnimalDTO {
}
class Zoo {
#JsonProperty(value = "Animals")
private AnimalDTO[] animals;
public AnimalDTO[] getAnimals() {
return animals;
}
public void setAnimals(AnimalDTO[] animals) {
this.animals = animals;
}
#Override
public String toString() {
return "Zoo [animals=" + Arrays.toString(animals) + "]";
}
}
class Data {
#JsonProperty(value = "Zoo")
private Zoo zoo;
public Zoo getZoo() {
return zoo;
}
public void setZoo(Zoo zoo) {
this.zoo = zoo;
}
#Override
public String toString() {
return "Data [zoo=" + zoo + "]";
}
}
This program prints:
{"Zoo":{"Animals":[{"type":"DogDTO","code":"001","name":"chihuahua"},{"type":"CatDTO","code":"002","name":"felix"}]}}