I'm new to Java. I'm using Spring to consume a REST api that outputs JSON. With the tutorials on the Spring website I can easily have the JSON response converted to an object of my desired class. The problem is now that one of the keys in the JSON response is $id. I cannot make a variable with a dollar sign in it. I assume I should define some configuration somewhere that such a name would be converted into something acceptable. I don't know how.
My Rest request code:
protected LoginResult doInBackground(Void... params) {
try {
Log.i(TAG, "Making Login request");
//TODO: Make this a setting
final String url = "https://someurl.com/api/login";
LoginCredentials login = new LoginCredentials("foo#bar.com", "qwerty123");
RestTemplate restTemplate = new RestTemplate();
restTemplate.getMessageConverters().add(new MappingJackson2HttpMessageConverter());
LoginResult result = restTemplate.postForObject(url, login, LoginResult.class);
Log.d(TAG, "Got the LoginResult.");
return result;
} catch (Exception e) {
//TODO: Exception handling
Log.e(TAG, e.getMessage(), e);
}
return null;
}
The resulting JSON looks something like this:
{
"_id":{
"$id":"98765432"
},
"name":"Person Guy",
"email":"foo#bar.com",
"roles":[
"user"
],
"active":true,
"created":{
"sec":1439117849,
"usec":856000
},
"session":{
"token":"12345678",
"user_id":"98765432",
"created":{
"sec":1439134272,
"usec":0
},
"last_extended":{
"sec":1439134272,
"usec":0
},
"expires":{
"sec":1439998272,
"usec":0
}
}
}
The $id part is where things get difficult. The LoginResult class looks like this:
#JsonIgnoreProperties(ignoreUnknown = true)
public class LoginResult {
private String name;
private String email;
private MongoId _id;
/* Getters and setters */
}
The MongoId class looks like this (The JsonIgnoreProperties is now added to avoid exceptions):
#JsonIgnoreProperties(ignoreUnknown = true)
public class MongoId {
private String id; //This is $id in the JSON response.
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
}
Any help would be largely appreciated.
You can use the #JsonProperty("$id") annotation in MongoId to tell how the JSON is mapped to your Java object:
#JsonIgnoreProperties(ignoreUnknown = true)
public class MongoId {
#JsonProperty("$id")
private String id; //This is $id in the JSON response.
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
}
Here is a quick overview for reference.
Related
I am trying to send one json from my frontend angular project to the backend which is springboot.
It is the first time I am using these 2 technologies so I lack in experience.
I am not quite sure if my http post method in Angular is wrong or if my backend isn't listening to the data which are supposed to come.
I will attach both code parts so that you can help me. Thank you in advance!
Here is a picture of the chrome console:
Http Errorcode 404
http error image
Backend:
#RestController
#RequestMapping
#CrossOrigin(origins = "http://localhost:4200")
public class RequestController {
private RolesRequestRepository rolesRequestRepository;
#PostMapping("/sendrolesrequest")
void addRequest(#RequestBody RolesRequest rolesRequest) {
rolesRequestRepository.save(rolesRequest);
}
#GetMapping("/sendrolesrequest")
public List<RolesRequest> getRequests() {
return (List<RolesRequest>) rolesRequestRepository.findAll();
}
}
#Entity
public class RolesRequest {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private long id;
private String requester = "";
private String recipient = "";
public RolesRequest(String recipient, String requester) {
this.recipient = recipient;
this.requester = requester;
}
public RolesRequest(){
}
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getRequester() {
return requester;
}
public void setRequester(String requester) {
this.requester = requester;
}
public String getRecipient() {
return recipient;
}
public void setRecipient(String recipient) {
this.recipient = recipient;
}
}
Here is the angular frontend part:
#Injectable()
export class RequestService {
sendRolesRequestUrl = 'sendrolesrequest'; // URL to web api
private handleError: HandleError;
constructor(
private http: HttpClient,
httpErrorHandler: HttpErrorHandler) {
this.handleError = httpErrorHandler.createHandleError('RequestService');
}
sendRolesRequest (rolesRequest: RequestModel): Observable<RequestModel> {
//console.log("addRolesRequest try post:" + rolesRequest.print());
return this.http.post<RequestModel>(this.sendRolesRequestUrl, rolesRequest, httpOptions)
.pipe(
catchError(this.handleError('sendRolesRequest', rolesRequest))
);
}
testPost() {
const headers = new Headers();
headers.append('Content-Type', 'application/json; charset=utf-8');
this.http.post(this.sendRolesRequestUrl, {'key1': 'value1', 'key2': 'value2'}, httpOptions)
.subscribe(() => {}, err => console.error(err));
}
}
export class RequestFormulaComponent implements OnInit {
onSendRequest() {
this.requestService
.sendRolesRequest(this.rolesRequest)
.subscribe();
}
}
I would be very happy if someone helps me out here. I am struggling on this topic over a week.
Is that even the way how a backend application should communicate with the webpage? If not, how can I do it otherwise?
You're using JPA entity as DTO, and have no setters/getters, also there is no default constuctor, modify your RolesRequest like this:
#Entity
public class RolesRequest {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private long id;
private String requester = "";
private String recipient = "";
public RolesRequest() { }
public RolesRequest(String recipient, String requester) {
this.recipient = recipient;
this.requester = requester;
}
public String getRequester() { return this.requester; }
public void setRequester(String r) { this.requester = r;}
public String getRecipient() { return this.recipient; }
public void setRecipient(String r) { this.recipient = r;}
Are your backend and angular app running on the same port? (backend and frontend are combined in the same application)
You are calling http://localhost:4200/sendrolesrequest and I think that's a request on the Angular app itself. You get a HTTP 404 error code (NOT FOUND)
You should call the endpoint of the backend application. It's running on port 8080 for example so call http://localhost:8080/sendrolesrequest (or with other port if backend is running on another port)
Change:
sendRolesRequestUrl = 'sendrolesrequest';
to:
sendRolesRequestUrl = 'http://localhost:8080/sendrolesrequest';
I am facing a problem while parsing API response using Retrofit 2.
The API's are already in production and I cannot request a change in API.
Following are two different responses I am getting from server
Success response:
{
"status":0,
"empId":121,
"message":"Data available",
"data":{
"name":"Sam",
"designation": "Software Engineer",
"mob": "1255565456"
}
}
Failure response
{
"status":10,
"empId":121,
"message":"No data available",
"data":""
}
Parsing Classes
class Response{
public int status;
public String message;
public int empId;
public Student data;
}
class Student{
public String name;
public String designation;
public String mob;
}
I am able to parse the success response. But getting the following exception for the failure case.
java.lang.IllegalStateException: Expected BEGIN_OBJECT but was STRING
try this ,
Object getrow = null;
try {
getrow = this.// your object
LinkedTreeMap<Object, Object> tree = (LinkedTreeMap) getrow;
String name = tree.get(<your body>).toString()
} catch (Exception e) {
e.printStackTrace();
}
The way that you can handle this situation is by treating 'data' as a generic object rather than as a String or 'Student'.
p̶u̶b̶l̶i̶c̶ ̶S̶t̶u̶d̶e̶n̶t̶ ̶d̶a̶t̶a̶;̶
public Object data;
While Using data add a check like this
if(data instanceof String){
String parsedData=data.toString();
}else{
Student parsedData= (Student) data;
}
Make Student as an inner class or Response class. and Retrofit will parse the response and will give you the object.
class Response
{
public int status;
public String message;
public int empId;
public Student data;
Class Data
{
public String name;
public String designation;
public String mob;
}
}
I am consuming a restful API which gives me the following response on a service call,
[
{
id=123,
cloudStatusTimestamp=2019-01-21T15:45:06.823,
cloudStatusCode=null,
cloudStatusMessage=300: PDF generated successfully,
cloudStatusComments=Inbound invoice,Reference: 123
}
,{
id=436,
cloudStatusTimestamp=2019-02-21T05:45:06.423,
cloudStatusCode=null,
cloudStatusMessage=300: PDF generated successfully,
cloudStatusComments=Inbound invoice, Reference: 456
}
]
I want to parse the above response to Java object. I manually tried to convert the response to JSON by replacing '=' by ':'and enclosing key and value pairs with quotes but it didn't work because some values are having ',' in between (cloudStatusComments=Inbound invoice, Reference: 456). Please share your comments.
The format of the JSON is not correct.
the format should be like this :
[
{
"id":123,
"cloudStatusTimestamp":"2019-01-21T15:45:06.823",
"cloudStatusCode":null,
"cloudStatusMessage":"300: PDF generated successfully",
"cloudStatusComments":"Inbound invoice",
"Reference": 123
},
{
"id":436,
"cloudStatusTimestamp":"2019-02-21T05:45:06.423",
"cloudStatusCode":null,
"cloudStatusMessage":"300: PDF generated successfully",
"cloudStatusComments":"Inbound invoice, Reference: 456"
}
]
hope this helps you out
Fisrt of all your json is incorrect, it should be in this format.
[
{
"id":123,
"cloudStatusTimestamp" : "2019-01-21T15:45:06.823",
"cloudStatusCode":null,
"cloudStatusMessage":"300: PDF generated successfully",
"cloudStatusComments":"Inbound invoice",
"Reference": 123
}
,{
"id":436,
"cloudStatusTimestamp":"2019-02-21T05:45:06.423",
"cloudStatusCode":null,
"cloudStatusMessage":"300: PDF generated successfully",
"cloudStatusComments":"Inbound invoice",
"Reference": 456
}
]
Now to parse this json, create following model class and get whatever field you want.
package com.example;
import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;
public class Example {
#SerializedName("id")
#Expose
private Integer id;
#SerializedName("cloudStatusTimestamp")
#Expose
private String cloudStatusTimestamp;
#SerializedName("cloudStatusCode")
#Expose
private Object cloudStatusCode;
#SerializedName("cloudStatusMessage")
#Expose
private String cloudStatusMessage;
#SerializedName("cloudStatusComments")
#Expose
private String cloudStatusComments;
#SerializedName("Reference")
#Expose
private Integer reference;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getCloudStatusTimestamp() {
return cloudStatusTimestamp;
}
public void setCloudStatusTimestamp(String cloudStatusTimestamp) {
this.cloudStatusTimestamp = cloudStatusTimestamp;
}
public Object getCloudStatusCode() {
return cloudStatusCode;
}
public void setCloudStatusCode(Object cloudStatusCode) {
this.cloudStatusCode = cloudStatusCode;
}
public String getCloudStatusMessage() {
return cloudStatusMessage;
}
public void setCloudStatusMessage(String cloudStatusMessage) {
this.cloudStatusMessage = cloudStatusMessage;
}
public String getCloudStatusComments() {
return cloudStatusComments;
}
public void setCloudStatusComments(String cloudStatusComments) {
this.cloudStatusComments = cloudStatusComments;
}
public Integer getReference() {
return reference;
}
public void setReference(Integer reference) {
this.reference = reference;
}
}
I need to send a json to a web address where this json will be consumed, basically I have a list of Dto's that I need to turn into a Json (with jackson).
Some information must be passed in the header:
timestamp= time, key= blablabla, accesskey= bla bla bla
As I have no experience with spring, i need to know how to do the HTTP request using Spring boot
(is it a post?)
Here's what I've implemented so far:
Student Dto Class
public class StudentDto {
private String name;
private String RM;
private String RG;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getRM() {
return RM;
}
public void setRM(String RM) {
this.RM = RM;
}
public String getRG() {
return RG;
}
public void setRG(String RG) {
this.RG = RG;
}
}
Turning my list of students into json
public String convertToJson(List obj) throws JsonProcessingException {
ObjectMapper mapper = new ObjectMapper();
String jsonInString = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(obj);
return jsonInString;
}
}
And this is the format json has to leave
{
"table": "student",
"rows":
[
{
"PersonID": 1,
"name": "Name",
"RM": "56656565",
"RG": "8787845-7",
},
{
"PersonID": 2,
"name": "Name",
"RM": "56656565",
"RG": "8787845-7"
}
]
}
below is and example of how to use rest template. You'll want to create a class for the request that has String table; and List<StudentDto> rows; as members
private static void createEmployee()
{
final String uri = "http://localhost:8080/springrestexample/employees";
MultiValueMap<String> headers = new MultiValueMap<>();
//set headers
HttpEntity<EmployeeVO> newEmployee = new HttpEntity<>(new EmployeeVO(-1, "Adam", "Gilly", "test#email.com"),headers);
RestTemplate restTemplate = new RestTemplate();
EmployeeVO result = restTemplate.postForObject( uri, newEmployee, EmployeeVO.class);
System.out.println(result);
}
*edit added headers
*edid look here for json formatting
you will also need to have the id field added to your object
The GET request to tenants/client/{hostname} returns a json object with the property baseApiHostname.
#GET("api/tenants/client/{hostname}")
Call<HostName> getHostname(#Path("hostname") String hostname);
baseApiHostname is successful retrieved. That hostname which is used to create the rest of tenant requests from.
Log.v("base url","testing "+preferenceManager.getTenantHostname());
retrofit = new Retrofit.Builder()
.client(okHttpClient)
.addConverterFactory(GsonConverterFactory.create(builder.create()))
.baseUrl(preferenceManager.getTenantHostname())
.build();
I received the error "java.lang.IllegalArgumentException: Illegal URL".
stacktrace message
After attaching debugger I realized that hostname = null.
debugger message
Call<HostName> call = hostNameApiService.getHostname(tenant);
call.enqueue(new Callback<HostName>() {
#Override
public void onResponse(Call<HostName> call, Response<HostName> response) {
if (response.isSuccessful()) {
String hostname = response.body().getBaseApiHostname();
preferenceManager.setTenantHostname(hostname);
retrieveCampaign();
} else {
Toast.makeText(StartSurveyActivity.this, "Error Retrieving Hostname", Toast.LENGTH_SHORT).show();
}
}
Here is the Hostname model class
#SerializedName("id")
private String id;
#SerializedName("name")
private String name;
#SerializedName("baseApiHostName")
private String baseApiHostname;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getBaseApiHostname() {
return baseApiHostname;
}
public void setBaseApiHostname(String baseApiHostname) {
this.baseApiHostname = baseApiHostname;
}
If there's any other detail required that will aid in helping myself and other developers who may have faced a similar problem, please don't hesistate to ask.
Thanks in advance guys.
GSON is not successfully serializing any response to the field you're retrieving, so there is some misalign in how you are setting up gson to parse your json result.
Given your object and your sample JSON, your field in JSON is "baseApiHostname" whereas in your object your GSON annotation is for serialized name "baseApiHostName".
You are setting null in your Retrofit.Builder for your base URL. What is the URL for your server? You need to set that for the first time. Then you can change it after that if need be but it can't be null the first time.