I'm using Retrofit to get some data from my WebAPI REST service. However my model contains a byte[] and this leads to an exception.
The exception I receive looks like this:
Caused by: retrofit.converter.ConversionException: com.google.gson.JsonSyntaxException: java.lang.IllegalStateException: Expected BEGIN_ARRAY but was STRING at line 1 column 122 path $.Photo
This exception appears because my model has a byte[] called Photo.
My model:
public class Artists {
private long ID;
private String Firstname;
private String Lastname;
private String Description;
private String Countrycode;
private byte[] Photo;
private java.util.Date Born;
private java.util.Date Death;
private java.util.Date Edited;
My REST API Java interface:
public interface ArtistRestService {
#GET("/artist/{id}")
Artists getArtist(#Path("id") long artistID);
#GET("/artist")
List<IdEditedRestObj> getArtists();
}
I know that I could use retrofit.mime.TypedByteArray but I also use GreenDAO an ORM mapper and I do not feel like to refactor the whole stack.
Is there an simple workaround/solution so I can somehow parse the incoming json so that exception does no take place?
Solution found:
Using https://github.com/square/retrofit/blob/master/retrofit-converters/jackson/src/main/java/retrofit/converter/JacksonConverter.java
public RestService(String url){
restAdapter = new RestAdapter.Builder()
.setClient(new OkClient(getClient()))
.setEndpoint(url)
.setConverter(new JacksonConverter())
.setErrorHandler(new RetrofitErrorHandler())
.setLogLevel(RestAdapter.LogLevel.HEADERS_AND_ARGS)
.build();
}
Everything works fine now, thx
Related
Im trying to send a post to my api using postman:
But its returning an error:
Resolved [org.springframework.http.converter.HttpMessageNotReadableException: JSON parse error: Cannot deserialize value of type java.time.LocalDate from String "10/11/2022": Failed to deserialize java.time.LocalDate: (java.time.format.DateTimeParseException) Text '10/11/2022' could not be parsed at index 0;
I tried to correct do the mapping with json mapping annotation in the dto class:
#Data
#Builder
public class OfertaEspecialDTO {
private String nome;
private final double desconto_percentual;
private String descricao;
#JsonFormat(pattern = "dd/MM/yyyy", shape = JsonFormat.Shape.STRING)
private LocalDate dataValidade;
}
But its still returning me the error.
How is the correct way to map my dateTime instance variable?
There is no issue with LocalDate instance variable mapping. Issue is with annotations used on top of class. Please refactor DTO class like this and try again.
#Setter
#Getter
public class OfertaEspecialDTO {
private String nome;
private double desconto_percentual;
private String descricao;
#JsonFormat(pattern = "dd/MM/yyyy", shape = JsonFormat.Shape.STRING)
private LocalDate dataValidade;
}
or like this
#Data
public class OfertaEspecialDTO {
private String nome;
private double desconto_percentual;
private String descricao;
#JsonFormat(pattern = "dd/MM/yyyy", shape = JsonFormat.Shape.STRING)
private LocalDate dataValidade;
}
I am new to JSON and spring. Was able to write simple examples consuming REST webservices. But as I apply to realtime scenario, the JSON is nested, and I don't have control in changing the structure.
Below code giving me Parse Error. Cannot deserialize instance of pg.domain.LookupDo[] out of START_OBJECT token
LookupDo[] lookupDos = template.exchange(url, HttpMethod.GET, request, LookupDo[].class).getBody();
How do I structure domain object?
#JsonIgnoreProperties
public class LookupDo {
private String companyCode;
private String plant;
private String category;
private String value;
private String descr;
You need to match your class with your JSON structure
Response res = template.exchange(url, HttpMethod.GET, request, Response.class).getBody();
LookupDo[] lookupDos = res.getD().getResults();
public class Response{
private Data d;
...
}
public class Data{
private LookupDo[] results;
...
}
I have a structure where there is a group which may contain leaf items or other groups too, so I implemented the Composite design pattern using a "SavedItem" interface with 2 subclasses "Rectangle" which represents the leaf node and "Group" where Group contains an arraylist of SavedItem objects to implement this composition hierarchy.
I used Gson to export the structure I have as a json file. The exported object is basically an arraylist of SavedItem objects and everything worked fine. However, the application requires loading a json file as well and converting it back to java objects, so I also used Gson but as I am trying to retrieve an arraylist of the interface "SavedItem" I am getting this exception:
Exception in thread "JavaFX Application Thread" java.lang.RuntimeException: Unable to invoke no-args constructor for interface SavedItem. Register an InstanceCreator with Gson for this type may fix this problem.
This is the "SavedItem" interface:
public interface SavedItem {
public String getId();
public String getDescription();
public Boolean getIsGroup();
public void addSavedItem(SavedItem savedItem);
}
This is the leaf node class "Rectangle" (of course with all setters and getters):
public class Rectangle implements SavedItem{
private String id;
private String type;
private String description;
private Point startingPoint ;
private double width;
private double height;
private boolean isGroup;
public Rectangle(){}
public Rectangle(Point startingPoint, double width, double height, String type , String description) {
this.id = "FIELD-" + UUID.randomUUID().toString();
this.startingPoint = startingPoint;
this.width = width;
this.height = height;
this.type= type;
this.description = description;
this.isGroup = false;
}
And this is the Group class (in addition to setters and getters):
public class Group implements SavedItem{
private String id;
private String description;
ArrayList<SavedItem> groupFields = new ArrayList<SavedItem>();
private boolean isGroup;
public Group(){}
public Group(String description) {
this.id = "GROUP-" + UUID.randomUUID().toString();
this.description = description;
this.isGroup = true;
}
The main object (called MedicalForm) contains this arraylist:
private ArrayList<SavedItem> StructuredFields = new ArrayList<>();
Creating the json file is done like this:
try {
Writer writer = new FileWriter(path+"/"+ form.getFormName()+".json");
Gson gson = new GsonBuilder().setPrettyPrinting().create();
JsonObject object = new JsonObject();
object.addProperty("id", form.getId());
object.addProperty("formName", form.getFormName());
JsonElement element = gson.toJsonTree(form.getStructuredFields());
object.add("StructuredFields", element);
object.addProperty("imageString", form.getImageString());
gson.toJson(object,writer);
writer.close();
} catch (IOException e) {
e.printStackTrace();
}
And loading a json and converting it back to java objects is done like this:
JsonReader reader = new JsonReader(new FileReader(path));
Gson gson = new Gson();
MedicalForm response = gson.fromJson(reader, MedicalForm.class);
form.setId(response.getId());
form.setFormName(response.getFormName());
form.setStructuredFields(response.getStructuredFields());
form.setImageString(response.getImageString());
I searched for the problem and I found solutions saying I should add a default constructor and so I did in both Group and Rectangle classes in addition to the class where I am trying to convert json to java object. However, I can't add a constructor in the interface, and replacing the interface with a superclass will prevent the flexibility of casting.
How can I solve this issue and convert the json properly to java objects?
I've been developing a cloud app to mess a little with Spring Cloud and such. Now I'm stuck trying to send a POST or a PUT request to a Spring Data Rest backend using the RestTemplate API but everything I tried ends with an error: HttpMessageNotReadableException: Cannot deserialize instance of java.lang.String out of START_OBJECT token, HttpMessageNotReadableException: Could not read document: Can not deserialize instance of java.lang.String out of START_ARRAY token, ...from request with content type of application/xml;charset=UTF-8!, Error 400 null... you name it. After researching I discovered that it actually is quite hard to consume HAL JSON with RestTemplate (level 3 JSON hypermedia if I recall correctly) but I want to know if it is possible.
I'd like to see some working (detailed if possible) examples of a RestTemplate sending POST and PUT to a Spring Data Rest backend.
Edit: I tried postForEntity, postForLocation, exchange and it just ended in different kinds of errors. Those are some snippets I tried (there're more, it's just that I dispose them).
My entity:
#Entity
public class Account implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
#NotNull
#NotEmpty
private String username;
#NotNull
#NotEmpty
private String authorities;
#NotNull
#NotEmpty
private String password;
//Constructor, getter and setter
Some restTemplate attemps:
public Account create(Account account) {
//Doesnt work :S
MultiValueMap<String, String> map = new LinkedMultiValueMap<String, String>();
map.add("name", account.getName());
map.add("username", account.getUsername());
map.add("password", account.getPassword());
map.add("authorities", account.getAuthorities());
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
final HttpEntity<MultiValueMap<String, String>> entity = new HttpEntity<MultiValueMap<String, String>>(map,
headers);
return restTemplate.exchange(serviceUrl + "/accounts", HttpMethod.POST, entity, Account.class).getBody();
}
//Also tried with a AccountResource which extends from ResourceSupport and doesn't work either. This one gives me a error saying it cannot deserialize Account["name"].
Also tried like this and got an error about header being application/xml: RestTemplate POSTing entity with associations to Spring Data REST server
The other ones just repeat one of those errors.
You need to configure your RestTemplate so it can consume the application/hal+json content type.
It has already been addressed in some other posts, such as this one or that one, and on a bunch of blog posts, such as here.
The following solution works for a Spring Boot project:
First, configure your RestTemplate using a bean:
// other import directives omitted for the sake of brevity
import static org.springframework.hateoas.MediaTypes.HAL_JSON;
#Configuration
public class RestTemplateConfiguration {
#Autowired
private ObjectMapper objectMapper;
/**
*
* #return a {#link RestTemplate} with a HAL converter
*/
#Bean
public RestTemplate restTemplate() {
// converter
MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
converter.setSupportedMediaTypes(Arrays.asList(HAL_JSON));
converter.setObjectMapper(objectMapper);
RestTemplate restTemplate = new RestTemplate(Collections.singletonList(converter));
return restTemplate;
}
}
Then, let Spring inject the RestTemplate where you need to consume the REST backend, and use one of the many variants of RestTemplate#exchange:
#Autowired
public RestTemplate restTemplate;
...
// for a single ressource
// GET
Account newAccount = restTemplate.getForObject(url, Account.class);
// POST
Account newAccount = restTemplate.exchange(serviceUrl + "/accounts", HttpMethod.POST, entity, Account.class).getBody();
// or any of the specialized POST methods...
Account newAccount = restTemplate.postForObject(serviceUrl + "/accounts", entity, Account.class);
For a collection, you will manipulate a PagedResources
// for a collection
ParameterizedTypeReference<PagedResources<Account>> responseType =
new ParameterizedTypeReference<PagedResources<Account>>() {};
// GET
PagedResources<Account> accounts =
restTemplate.exchange(url, HttpMethod.GET, null, responseType).getBody();
//
I am trying to implement a RESTful Web Service with Jackson and Jersey Servlets. My Webservices can produce this particular JSON as shown
{
"email":"aditya#123.com",
"source":{
"G":33.2470567,
"K":-95.89996559999997
},
"destination":{
"G":33.0198431,
"K":-96.69888559999998
},
"waypoints":[
{
"location":"Dallas, TX, USA",
"stopover":true
},
{
"location":"Houston, TX, USA",
"stopover":true
}
]
}
But when I try to consume the Same JSON it gives an internal server 500 error:
org.codehaus.jackson.JsonParseException: Unexpected character ('Â' (code 194)): was expecting double-quote to start field name
My POJOs & web service is as shown:
#XmlRootElement
public class RiderVO {
private String email;
private MapLocation source;
private MapLocation destination;
private List<Waypoint> waypoints;
//getters and setters
}
#XmlRootElement
public class MapLocation {
private Double G;
private Double K;
//getters and setters
}
#XmlRootElement
public class Waypoint {
private String location;
private Boolean stopover;
//getters & setters
}
WEB SERVICE:
#POST
#Path("/saveAll")
#Consumes(MediaType.APPLICATION_JSON)
#Produces(MediaType.APPLICATION_JSON)
public String saveRideJson(RiderVO riderVO){
//do something
}
I cannot figure out when it can produce a particular JSON why cannot I consume it. I did try changing the boolean parameters, and check if its isVar setter issues like here. But even that did not fix. Any suggestions are helpful. Thanks in advance!