updating JSON Object in spring restful web services - json

I want to pass a json object for the update function but its doesn't accept the json object and get an error. The error is:
the code is:
(value = "/UpdateUser/", method = RequestMethod.PUT , consumes=MediaType.APPLICATION_JSON_VALUE)
public void UpdateUser(JSONObject RequiredObject)throws UnknownHostException {
// RequiredObject=new HashMap<>();
System.out.println("hello into update " + RequiredObject);
// readJSON.UpdateUser(RequiredObject);
}

you have to receive the body of your request as a #RequestBody and you can receive this json object as a User object directly
#RequestMapping(value = "/UpdateUser/", method = RequestMethod.PUT ,
consumes=MediaType.APPLICATION_JSON_VALUE)
public void UpdateUser(#RequestBody User user) throws UnknownHostException {
// RequiredObject=new HashMap<>();
System.out.println("hello into update " + RequiredObject);
//readJSON.UpdateUser(RequiredObject);
}

Related

How to handle timeout exception in quarkus?

I am trying to connect to a third-party API from quarkus controller . I have a controller using the method of service. The try catch block is not working.I have all the required dependency and i followed quarkus doc
Here is the code
Controller
package com.ncr.invoice;
// all imports over here
#Path("/api")
#RequestScoped
public class InvoiceController {
// all variable and injection
#POST
#Consumes(MediaType.APPLICATION_JSON)
#Produces(MediaType.APPLICATION_JSON)
#Path("/invoice")
#Timeout(250)
#PermitAll
public Response getInvoice(AuthTokenRequestModel atrm){
SoupResponseInvoiceDetail srid = null;
try{
srid = service.getInvoice(
atrm.getMcn(),"transactionId", atrm.getInvoiceNumber()
);
LOG.info("try block end");
}
catch(InterruptedException e)
{
LOG.info("Over here");
return Response.status(401).build();
}
return Response.ok(srid).build();
}
return Response.status(401).build();
}
// all getter setter
}
service
package com.ncr.invoice;
//all imports
#Path("/")
#RegisterRestClient(configKey="invoice-api")
#ClientHeaderParam(name = "Authorization", value = "{basicAuth}")
public interface InvoiceService {
#GET
#Produces(MediaType.APPLICATION_JSON)
#Path("/")
public SoupResponseInvoiceDetail getInvoice(#QueryParam("id") String id,#QueryParam("txn_id") String txnId, #QueryParam("invoice") String invoice) throws InterruptedException;
default String basicAuth() {
String uName = ConfigProvider.getConfig().getValue("auth.username", String.class);
String pwd = ConfigProvider.getConfig().getValue("auth.pwd", String.class);
String creds = uName + ":" + pwd;
return "Basic " + Base64.getEncoder().encodeToString(creds.getBytes());
}
}
Error that i am getting
2021-01-07 13:07:42,286 INFO [com.ncr.inv.InvoiceController] (executor-thread-189) try block end
2021-01-07 13:07:42,555 ERROR [io.und.req.io] (executor-thread-189) Exception handling request 58a6d4b3-76c1-4a8b-b4a0-1e241219fb4d-4 to /api/invoice: org.jboss.resteasy.spi.UnhandledException: org.eclipse.microprofile.faulttolerance.exceptions.TimeoutException: Timeout[com.ncr.invoice.InvoiceController#getInvoice] timed out
at org.jboss.resteasy.core.ExceptionHandler.handleApplicationException(ExceptionHandler.java:106)
at org.jboss.resteasy.core.ExceptionHandler.handleException(ExceptionHandler.java:372)
at org.jboss.resteasy.core.SynchronousDispatcher.writeException(SynchronousDispatcher.java:218)
at org.jboss.resteasy.core.SynchronousDispatcher.invoke(SynchronousDispatcher.java:519)
at org.jboss.resteasy.core.SynchronousDispatcher.lambda$invoke$4(SynchronousDispatcher.java:261)
at org.jboss.resteasy.core.SynchronousDispatcher.lambda$preprocess$0(SynchronousDispatcher.java:161)
.........................................
To me it look like you need to need to do something like this:
#Provider
public class TimeoutExceptionMapper implements ExceptionMapper {
private static final Logger LOGGER = LoggerFactory.getLogger(java.lang.invoke.MethodHandles.lookup().lookupClass());
#Override
public Response toResponse(TimeoutException exception) {
LOGGER.warn(exception.getMessage());
return getResponse();
}
public static Response getResponse() {
ErrorResponse response = new ErrorResponse();
response.setDescription("Operation timet out, try again later");
return status(Response.Status.GATEWAY_TIMEOUT).entity(response).build();
}
}

How to run JUnit testing on Firebase Java with authentication?

I am currently using Firebase Authentication in my mobile app. The back end is a Spring boot application. The REST APIs on the back end relies on a token generated from Firebase Authentication to retrieve the Firebase UID (verifyIDToken method) of a user to perform further functions.
Currently, I notice that in Firebase Java API (server-based), there is no way of generating a token for a user, thus there is no easy way for me to do JUnit testing on the server that relies on user authentication. Anyone has clues on how to do so?
This is the sample code that does not work:
#RequestMapping(value = "/api/subscribeChannel/{channelid}", method = RequestMethod.GET, produces = "application/json")
public DeferredResult<Object> subscribeChannel(#PathVariable Long channelid,#RequestHeader(value=FIREBASETOKEN, required = true) String idToken) {
DeferredResult<Object> result = new DeferredResult<Object>(DEFERREDTIMEOUT);
// test it out with a locally generated token
idToken = FirebaseAuth.getInstance().createCustomToken("valid Uid");
Task<FirebaseToken> task = FirebaseAuth.getInstance().verifyIdToken(idToken)
.addOnSuccessListener(new OnSuccessListener<FirebaseToken>() {
#Override
public void onSuccess(FirebaseToken decodedToken) {
String uid = decodedToken.getUid();
logger.info("Subscribe channel on success");
// do something
ret.setStatus("success");
ret.setMessage("channel id " + channelid + " subscribed");
result.setResult(ret);
} else {
result.setErrorResult(retStatus.getMessage());
}
}
}) .addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(Exception arg0) {
Exception te = new TokenNotFoundException(idToken);
logger.error("Token Not Found for " + idToken);
result.setErrorResult(te);
}
});
return result;
}
The custom token you get is different from the ID token that you use to log on. To get an id token from a custom token, do this:
private static final String ID_TOOLKIT_URL =
"https://www.googleapis.com/identitytoolkit/v3/relyingparty/verifyCustomToken";
private static final JsonFactory jsonFactory = Utils.getDefaultJsonFactory();
private static final HttpTransport transport = Utils.getDefaultTransport();
private static final String FIREBASE_API_KEY = "<your api key here>";
private String signInWithCustomToken(String customToken) throws IOException {
GenericUrl url = new GenericUrl(ID_TOOLKIT_URL + "?key="
+ FIREBASE_API_KEY);
Map<String, Object> content = ImmutableMap.<String, Object>of(
"token", customToken, "returnSecureToken", true);
HttpRequest request = transport.createRequestFactory().buildPostRequest(url,
new JsonHttpContent(jsonFactory, content));
request.setParser(new JsonObjectParser(jsonFactory));
com.google.api.client.http.HttpResponse response = request.execute();
try {
GenericJson json = response.parseAs(GenericJson.class);
return json.get("idToken").toString();
} finally {
response.disconnect();
}
}
The Java API to generate custom tokens is documented under Create custom tokens using the Firebase SDK.
From there:
String uid = "some-uid";
String customToken = FirebaseAuth.getInstance().createCustomToken(uid);

Forward JSON POST request from one REST API to another

I have the following situation:
My REST API one:
#RestController
#RequestMapping("/controller1")
Public Class Controller1{
#RequestMapping(method = RequestMethod.POST)
public void process(#RequestBody String jsonString) throws InterruptedException, ExecutionException
{
............
}
}
JSON POST request, request1, for the REST API(Controller1):
{
"key1":"value1",
"key2":"value2"
}
My REST API two:
#RestController
#RequestMapping("/controller2")
Public Class Controller2{
#RequestMapping(method = RequestMethod.POST)
public void process(#RequestBody String jsonString) throws InterruptedException, ExecutionException
{
............
}
}
JSON request, request2, for the REST API(Controller2):
{
"key1":"value1",
"key2":"value2",
"key3":"value3"
}
I have several such "primitive" requests.
Now, I am expecting a JSON request, let's call it request3, which is a combination of such "primitive" queries- something that looks like below:
{
{
"requestType":"requestType1",
"request":"[{"key1":"value1","key2":"value2"}]"
},
{
"requestType":"requestType2",
"request":"[{"key1":"value1","key2":"value2","key3":"value3"}]"
}
}
Here, I need to trigger the respective API (one or two) upon identifying the query type. I wanna know how I can forward the request to the corresponding REST API. I wrote the REST API for request3 like below:
#RestController
#RequestMapping("/controller3")
Public Class Controller3{
#RequestMapping(method = RequestMethod.POST)
public void process(#RequestBody String jsonString) throws InterruptedException, ExecutionException
{
..................
..................
switch(request){
case request1: //how to call REST API 1?
case request2: //how to call REST API 2?
}
}
}
You can call a utility method which posts request to controller using Rest Template as below. Since you are using POST method it's easy to send parameters using Rest Template. You may need to edit this code a bit to work in your environment with exact syntax.
#RequestMapping( value= "/controller3" method = RequestMethod.POST)
public #ResponseBody void process(#RequestBody String jsonString){
String request = requestType //Get the request type from request
String url = "";
MultiValueMap<String, String> params= null;
switch(request){
case request1: //how to call REST API 1?
url = "/controller1";
params = request1param //Get the parameter map from request
case request2: //how to call REST API 2?
url = "/controller2";
params = request2Param //Get the parameter map from request
}
//Now call the method with parameters
getRESTResponse(url, params);
}
private String getRESTResponse(String url, MultiValueMap<String, String> params){
RestTemplate template = new RestTemplate();
HttpEntity<MultiValueMap<String, String>> requestEntity=
new HttpEntity<MultiValueMap<String, String>>(params);
String response = "";
try{
String responseEntity = template.exchange(url, HttpMethod.POST, requestEntity, String.class);
response = responseEntity.getBody();
}
catch(Exception e){
response = e.getMessage();
}
return response;
}
Redirect from one controller method to another controller method
Alternatively you also can call the rest method using Rest Template
Spring MVC - Calling a rest service from inside another rest service
You may find how to send POST request with params in this post
https://techie-mixture.blogspot.com/2016/07/spring-rest-template-sending-post.html

sending arraylist from a rest service

I am new to webservices and also REST. I am trying to send a message as a post request to a rest service using rest java client.I am trying to get response of previous requests also(everything in json format). So, am storing the message objects into an arraylist and sending the list as a reponse. But I am not able to get the previous messages. Please tell me if am doing anything wrong.
This is my message model class.
public class Messages {
private String id;
private String message;
public Messages() {
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
the following is my webservice to receive a message object and return a json array.
#Path("/json/messages")
public class JSONMessages {
public List<Messages> list = new ArrayList<Messages>();
List<Messages> getAllMessages(Messages m){
list.add(m);
return list;
}
#POST
#Path("/post")
#Consumes(MediaType.APPLICATION_JSON)
#Produces(MediaType.APPLICATION_JSON)
public Response MessageListInJSON(Messages msg) {
System.out.println("message saved");
if(!(msg.getId().equals("1"))){
String output ="Invalid User";
return Response.ok(output).build();
}
else{
return Response.ok(getAllMessages(msg)).build();
}
}
}
Finally, the following is my client side code
public class ClientPost {
public static void main(String[] args) {
try {
ClientConfig clientConfig = new DefaultClientConfig();
Client client = Client.create(clientConfig);
WebResource webResource = client
.resource("http://localhost:8050/lab.rest.webservices/rest/json/messages/post");
//for(int i=0;i<5;i++){
String input = "{\"id\":\"1\", \"message\":\"hey there!\"}";
ClientResponse response = webResource.accept("application/json").type("application/json")
.entity(input).post(ClientResponse.class);
if (response.getStatus() !=200 ) {
throw new RuntimeException("Failed : HTTP error code : "
+ response.getStatus());
}
System.out.println("Output from Server .... \n");
String output = response.getEntity(String.class);
System.out.println(output+"\n");
}
catch (Exception e) {
e.printStackTrace();
}
} }
Now, what I am expecting to see is the message I sent along with the previous responses stored in the array list(which were sent by running the client multiple times manually for now) but always am ending up with only the current message.
output:
Output from Server ....
[{"id":"1","message":"hey there!"}]
To be precise, what I want as output when i run my client several times(or put the try block in loop) is as follows which i am unable to get.
Output from Server ....
[{"id":"1","message":"hey there!"},{"id":"1","message":"hey there!"},{"id":"1","message":"hey there!"},{"id":"1","message":"hey there!"}] .
Resources in JAXRS aren't singletons. That means that for each request, the class JSONMessages is instantiated. So you lose the content of the attribute list. Changing it to static could fix your problem.
There is an annotation Singleton to change this behavior. In this case the resource will be managed as singleton and not in request scope. Here is a sample:
#Singleton
#Path("/json/messages")
public class JSONMessages {
(...)
}
Otherwise, be careful of concurrent accesses on your list. See this question for more details: java concurrent Array List access.
Hope it helps you,
Thierry

Getting issue while parsing json using jackson

i am using jackson to parse data i am using following code to parse json
public Map<String, Object> savePreference(#RequestBody Map map) throws IOException{
List preferenceDetails = (List) map.get("data");
int preferenceIndex = 0;
while(preferenceIndex < preferenceDetails.size()){
final ObjectMapper mapper = new ObjectMapper();
System.out.println(preferenceDetails.get(preferenceIndex));
mapper.readValue(preferenceDetails.get(preferenceIndex).toString(), Preference.class);
preferenceIndex++;
}
return null;
}
i am sending json from client side like this
{"data":[
{
"preferenceType":"Travelling"
},
{
"preferenceType":"Shopping"
}
]
}
but above code throws exception when i called
mapper.readValue(preferenceDetails.get(preferenceIndex).toString(), Preference.class);
exception is
com.fasterxml.jackson.core.JsonParseException: Unexpected character ('p' (code 112)): was expecting double-quote to start field name
i am printing preference details in while loop
{preferenceType=Travelling}
You do not need to parse line by line. Using objects directly will be much more easier. Here is a test case which demonstrates how to parse your json to a object directly.
import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.Assert;
import org.junit.Test;
import java.util.Collection;
public class JacksonTest {
#Test
public void testName() throws Exception {
final String test = "{\"data\":[\n" +
" {\n" +
" \"preferenceType\":\"Travelling\"\n" +
" },\n" +
" {\n" +
" \"preferenceType\":\"Shopping\"\n" +
" }\n" +
" ]\n" +
"}";
final ObjectMapper objectMapper = new ObjectMapper();
final Data data = objectMapper.readValue(test, Data.class);
Assert.assertNotNull(data);
Assert.assertEquals(2, data.getData().size());
}
static class Data {
private Collection<PreferenceType> data;
public Collection<PreferenceType> getData() {
return data;
}
public void setData(Collection<PreferenceType> data) {
this.data = data;
}
}
static class PreferenceType {
private String preferenceType;
public String getPreferenceType() {
return preferenceType;
}
public void setPreferenceType(String preferenceType) {
this.preferenceType = preferenceType;
}
}
}
After that you can build your own map how ever you want. But your framework may be able to handle this kind of request. You do not need to parse it manually. You should try getting Data object directly, instead of getting your body as Map.
Update
Try something like this. But first define Data class properly ( at least not as an inner class).
public Map<String, Object> savePreference(#RequestBody Data data) throws IOException{
...
}
Update 2
And also your map already has your object PreferenceDetail. It may already handle the json and map it as object. Please debug and check if your map.get("data") returns List<PreferenceDetail> or not. If it returns List there is no more work is needed to parse json using jackson. You can simply do something like this.
public Map<String, Object> savePreference(#RequestBody Map map) throws IOException{
List<PreferenceDetail> preferenceDetails = (List) map.get("data");
for (PreferenceDetail preferenceDetail : preferenceDetails) {
System.out.println(preferenceDetail.getPreferenceType());
}
return null;
}
I solved my problem by using jackson object mapper.
public Map<String, Object> savePreference(#RequestBody Map map) throws IOException{
log.debug("saving preferences");
if(preferenceService.getPreferencesByUser() != null && preferenceService.getPreferencesByUser().size() != 0)
return ResponseHandler.generateResponse(configProp.getProperty("user.preference.exist"), HttpStatus.ACCEPTED, true, null);
final ObjectMapper mapper = new ObjectMapper();
List preferenceDetails = (List) map.get("data");
int preferenceIndex = 0;
while(preferenceIndex < preferenceDetails.size()){
preferenceService.savePreference(mapper.readValue(mapper.writeValueAsString(preferenceDetails.get(preferenceIndex)), Preference.class));
preferenceIndex++;
}
return ResponseHandler.generateResponse(configProp.getProperty("preference.added"), HttpStatus.ACCEPTED, true, null);
}