Spring is refusing to send a ResponseEntity but does not throw exceptions - java

My POJO/data model:
public class CanResendResponse {
#JsonProperty(value = "canResend")
#NotEmpty
public Boolean canResend;
// getters, setters & ctors
}
My Spring Boot controller & method:
#RestController
#RequestMapping("v1/data/fizzes")
class FizzResource {
#GetMapping(value = "{fizzId}/canResend")
public void canResendVerifications(#PathVariable(value = "fizzId") String fizzId) {
Fizz fizz = fizzRepository.findById(fizzId);
Boolean canResend;
System.out.println("Fizz name:" + fizz.getName());
if(fizz.canResend()) {
canResend = Boolean.TRUE;
} else {
canResend = Boolean.FALSE;
}
return new ResponseEntity<CanResendResponse>(new CanResendResponse(canResend), HttpStatus.OK);
}
}
My curl command:
curl -H "Content-Type: application/json" -X GET https://localhost:9200/v1/data/fizzes12345/canResend
When I run the curl command I don't see any exceptions/error on the server side and the curl completes without error but I do not see the expected HTTP response entity, like:
{
"canResend" : "true"
}
However I do see the Fizz name: Joe message in STDOUT.
I've confirmed the same behavior in a browser (I punch https://localhost:9200/v1/data/fizzes12345/canResend) into a browser and the response/page is empty. Any ideas as to what I can do to fix this?

Your method has VOID return type. Try this:
#GetMapping(value = "{fizzId}/canResend")
public ResponseEntity canResendVerifications(#PathVariable(value = "fizzId") String fizzId) {
Your method code goes here...
}

Change
public void canResendVerifications(#PathVariable(value = "fizzId") String fizzId) {
to
public ResponseEntity<> canResendVerifications(#PathVariable(value = "fizzId") String fizzId) {
... and make sure you return that ResponseEntity.

Related

Spring boot & Java - HTTP Status 404 error aka white-label error

Please have a look at my codes below. The Java codes seemed to work just fine, but localhost:8080 gives me the error code 404 when I try to access it. I want to make localhost 8080 work. Please let me know if you need further information.
Application
#SpringBootApplication(exclude = { ErrorMvcAutoConfiguration.class })
// exclude part is to elimnate whitelabel error
#EnableScheduling
public class Covid19TrackerApplication {
public static void main(String[] args) {
SpringApplication.run(Covid19TrackerApplication.class, args);
}
}
Controller
#Controller
public class HomeController {
CovidDataService covidDataService;
#RequestMapping("/")
public #ResponseBody String home(Model model) {
model.addAttribute( "locationStats", covidDataService.getAllStats());
return "home";
}
}
Main Code
#Service
public class CovidDataService {
private static String Covid_Data_URL = "https://raw.githubusercontent.com/CSSEGISandData/COVID-19/master/csse_covid_19_data/csse_covid_19_time_series/time_series_covid19_confirmed_global.csv";
private List<LocationStats> allStats = new ArrayList<>();
public List<LocationStats> getAllStats() {
return allStats;
}
#PostConstruct//?
#Scheduled(cron = "* * 1 * * *") //????
// * sec * min *hour and so on
public void fetchCovidData() throws IOException, InterruptedException {
List<LocationStats> newStats = new ArrayList<>(); // why we are adding this? To prevent user get an error while we are working on new data.
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(Covid_Data_URL))
.build(); // uri = uniform resource identifier
HttpResponse<String> httpResponse = client.send(request, HttpResponse.BodyHandlers.ofString());
StringReader csvBodyReader = new StringReader(httpResponse.body()); //StringReader needs to be imported
Iterable<CSVRecord> records = CSVFormat.DEFAULT.withFirstRecordAsHeader().parse(csvBodyReader); // parse(in) had error, we needed a "reader" instance.
for (CSVRecord record : records) {
LocationStats locationStat = new LocationStats(); //create an instance
locationStat.setState(record.get("Province/State"));
locationStat.setCountry(record.get("Country/Region"));
locationStat.setLatestTotalCase(Integer.parseInt(record.get(record.size()-1)));
System.out.println(locationStat);
newStats.add(locationStat);
}
this.allStats = newStats;
}
}
The problem may come from this piece of code
#RequestMapping("/")
public #ResponseBody String home(Model model) {
model.addAttribute( "locationStats", covidDataService.getAllStats());
return "home";
}
it returns "home" which should be existing view, normally, the view will be a jsp file which is placed somewhere in WEB-INF, please see this tutorial: https://www.baeldung.com/spring-mvc-view-resolver-tutorial
In the case of wrong mapping, it may returns 404 error
when you run the server, you should be able to see which port it's taken in the console.
Also, is server.port=8080 in the src/main/resources/application.properties file?
In the controller, the RequestMapping annotation is missing the method type and header
#RequestMapping(
path="/",
method= RequestMethod.GET,
produces=MediaType.APPLICATION_JSON_VALUE)
public String home(Model model) {
model.addAttribute( "locationStats", covidDataService.getAllStats());
return "home";
}
make sure to add consumes for POST or PUT methods
A bit unrelated to the question but the line in the controller is missing #Autowired annotation
CovidDataService covidDataService;
Preferrably, add the #Autowired in the constructor
#Autowired
public HomeController(CovidDataService covidDataService) {
this.covidDataService = covidDataService;
}

Apache CXF Spring rest service POST request returns "msg" : "Stream closed"

I work with an Apache Cxf, Spring Jax-rs service and I have the following service definition and the implementations provided,
THE DEFINITION
#POST
#Path("/generateAddress")
#Consumes(MediaType.APPLICATION_JSON)
#Produces({MediaType.APPLICATION_JSON})
WalletInfo generateAddress(final String walletName, String currencyName);
THE IMPLEMENTATIONS
public synchronized WalletInfo generateAddress(final String walletName, String currencyName) {
WalletInfo walletInfo = IWalletInfoDao.getWalletInfoWithWalletNameAndCurrency(walletName, currencyName);
return walletInfo;
}
When I do the POST request with the cURL like
curl -H "Content-Type: application/json" -X POST -d '{"walletName":"Icecream5500","currencyName":"Bitcoin"}' http://localhost:8080/api/rest/wallet/generateAddress
I get the JSON response back,
{
"msg" : "Stream closed",
"date" : "2017-08-28T09:22:027Z"
}
I'm pretty sure that the generateAddress method works fine. What is
the issue here and particularly, when you would get the message Stream closed in the Spring Apache Cxf project while doing the POST requests? Obviously, I can provide more info if required. The server log is normal and I see nothing unusual.
The POST body doesn't match with the parameters of the method and this created the issue in the first place. I have solved the problem in the following options.
I created a new class
public class CreateWalletWithNameAndCurrency {
String walletName;
String currencyName;
public CreateWalletWithNameAndCurrency(String walletName, String currencyName) {
this.walletName = walletName;
this.currencyName = currencyName;
}
public CreateWalletWithNameAndCurrency() {
}
public String getWalletName() {
return walletName;
}
public String getCurrencyName() {
return currencyName;
}
public void setCurrencyName(String currencyName) {
this.currencyName = currencyName;
}
public void setWalletName(String walletName) {
this.walletName = walletName;
}
}
I changed the definition of the POST request like this,
#POST
#Path("generateAddress")
#Consumes(MediaType.APPLICATION_JSON)
#Produces({MediaType.APPLICATION_JSON})
WalletInfo generateAddress(CreateWalletWithNameAndCurrency createWalletWithNameAndCurrency);
The implementation is provided below,
public synchronized WalletInfo generateAddress(CreateWalletWithNameAndCurrency createWalletWithNameAndCurrency) {
String walletName = createWalletWithNameAndCurrency.getWalletName();
String currencyName = createWalletWithNameAndCurrency.getCurrencyName();
WalletInfo walletInfo = iWalletInfoDao.getWalletInfoWithWalletNameAndCurrency(walletName, currencyName);
// some more code
}
Finally, I can do the POST request like this,
curl -H "Content-Type: application/json" -X POST -d '{"walletName":"Copenhangen","currencyName":"Bitcoin"}' http://localhost:8080/rest/wallet/generateAddress

Why is JsonHttpContent's output empty?

I am using Google Http Client library (1.20) on Google App Engine (1.9.30) to submit a POST request to Google Cloud Messaging (GCM) servers. Here's the code:
public static HttpRequestFactory getGcmRequestFactory() {
if (null == gcmFactory) {
gcmFactory = (new UrlFetchTransport())
.createRequestFactory(new HttpRequestInitializer() {
#Override
public void initialize(HttpRequest request) throws IOException {
request.getHeaders().setAuthorization(
"key=" + Config.get(Config.Keys.GCM_SERVER_API_KEY).orNull());
request.getHeaders().setContentType("application/json");
request.getHeaders().setAcceptEncoding(null);
}
});
}
return gcmFactory;
}
public static JsonFactory getJsonFactory() {
return jacksonFactory;
}
public static String sendGcmMessage(GcmDownstreamDto message) {
HttpRequestFactory factory = getGcmRequestFactory();
JsonHttpContent content = new JsonHttpContent(getJsonFactory(), message);
String response = EMPTY;
try {
HttpRequest req = factory.buildPostRequest(gcmDownstreamUrl, content);
log.info("req headers = " + req.getHeaders());
System.out.print("req content = ");
content.writeTo(System.out); // prints out "{}"
System.out.println(EMPTY);
HttpResponse res = req.execute(); // IOException here
response = IOUtils.toString(res.getContent());
} catch (IOException e) {
log.log(Level.WARNING, "IOException...", e);
}
return response;
}
Now the content.writeTo() always prints out empty JSON. Why is that? What am I doing wrong? The GcmDownstreamDto class (using Lombok to generate getters and setters):
#Data
#Accessors(chain = true)
public class GcmDownstreamDto {
private String to;
private Object data;
private List<String> registration_ids;
private GcmNotificationDto notification;
public GcmDownstreamDto addRegistrationId(String regId) {
if (null == this.registration_ids) {
this.registration_ids = new ArrayList<>();
}
if (isNotBlank(regId)) {
this.registration_ids.add(regId);
}
return this;
}
}
The immediate goal is to generate the same response as (from Checking the validity of an API key):
api_key=YOUR_API_KEY
curl --header "Authorization: key=$api_key" \
--header Content-Type:"application/json" \
https://gcm-http.googleapis.com/gcm/send \
-d "{\"registration_ids\":[\"ABC\"]}"
{"multicast_id":6782339717028231855,"success":0,"failure":1,
"canonical_ids":0,"results":[{"error":"InvalidRegistration"}]}
I've already tested using curl so I know the API key is valid, I just want to do the same thing in Java code to build up my base classes.
sendGcmMessage() is being invoked as follows:
#Test
public void testGcmDownstreamMessage() {
GcmDownstreamDto message = new GcmDownstreamDto().addRegistrationId("ABC");
System.out.println("message = " + message);
String response = NetCall.sendGcmMessage(message);
System.out.println("Response: " + response);
}
All help appreciated.
Found out the problem: it's the way JacksonFactory().createJsonGenerator().searialize() works (I was expecting it to serialize the way ObjectMapper serializes). This is the code for JsonHttpContent.writeTo() (from JsonHttpContent.java in google-http-java-client):
public void writeTo(OutputStream out) throws IOException {
JsonGenerator generator = jsonFactory.createJsonGenerator(out, getCharset());
generator.serialize(data);
generator.flush();
}
The Jackson JsonGenerator expects a key-value pairing (represented in Java as Map) which is not obvious from the constructor signature of the JsonHttpContent constructor: JsonHttpContent(JsonFactory, Object).
So if instead of passing a GcmDownstreamDto (as defined in the question, which is what would have worked with an ObjectMapper), I were to do the following:
Map<String, Object> map = new HashMap<>();
List<String> idList = Arrays.asList("ABC");
map.put("registration_ids", idList);
everything works as expected and the output is:
{"registration_ids":["ABC"]}
So just remember to pass the JsonHttpContent(JsonFactory, Object) constructor a Map<String, Object> as the second parameter, and everything will work as you would expect it to.
You need to annotate the POJO fields with #Key:
import com.google.api.client.util.Key;
// ...
#Key private String to;
#Key private Object data;
#Key private List<String> registration_ids;
// ...

Required request body is missing

I am new at Spring and Rest.
I wrote a simple rest like this:
#RequestMapping(value = "/loginTest", method = RequestMethod.POST)
#ResponseBody
public Response loginTest(#RequestBody LoginRequest request) {
System.out.println("enter loginTest.");
String account = request.getAccount();
String password = request.getPassword();
Response res = new Response();
return res;
}
And the LoginRequest is like this:
public class LoginRequest {
private String account;
private String password;
public String getAccount() {
return account;
}
public void setAccount(String account) {
this.account = account;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
When I test this via command:
curl -X POST "{"account": "aaa","password": "bbb"}" -H "Content-type:application/json" http://localhost:8080/user/loginTest
But I got the result:
[1/2]: account: aaa --> <stdout>
--_curl_--account: aaa
curl: (6) Could not resolve host: account; nodename nor servname provided, or not known
{
"timestamp" : "2015-12-30T16:24:14.282+0000",
"status" : 400,
"error" : "Bad Request",
"exception" : "org.springframework.http.converter.HttpMessageNotReadableException",
"message" : "Bad Request",
"path" : "/user/loginTest"
}
And also in eclipse console:
Failed to read HTTP message: org.springframework.http.converter.HttpMessageNotReadableException: Required request body is missing: public com.test.response.Response com.test.service.UserService.loginTest(com.test.model.request.LoginResquest)
Does the class LoginRequest need an annotation? Because the Jason cannot be converted to a class?
Would anyone help me figure this out?
Request body should be sent in --data switch, in curl.
See this https://superuser.com/questions/149329/what-is-the-curl-command-line-syntax-to-do-a-post-request
So your request should now become
curl -X POST --data '{"account": "aaa","password": "bbb"}' -H "Content-Type:application/json" http://localhost:8080/user/loginTest
Also if you can run a browser on the machine where you're sending the requests from, then you can try some REST client plugins. They're way easier to use and provide saving requests and history features.
Check this plugin

Spring: Request method 'PUT' not supported

I started with one of the Spring getting started samples. I am extending it to match my scenario. I am trying to use the PUT method on a web service call. I get the error message "Request method 'PUT' not supported". But, execution makes it into the web service. The error occurs after/during returning. Is there something I need to do to my objects to allow the to be returned from non-GET HTTP methods?
I am calling into the web service with a test stub written in python. I have not posted that code since execution is getting into the web service.
Following is the Spring code:
#ComponentScan
#EnableAutoConfiguration
#Controller
#RequestMapping("/jp5/rest/message")
public class MessageRestService
{
#RequestMapping(method=RequestMethod.PUT, value="/test")
public testResult test()
{
// I hit a breakpoint here:
return new testResult(true, "test");
}
}
class testResult
{
public testResult( boolean success, String message )
{
setSuccess(success);
setMessage(message);
}
//#XmlElement
private boolean success;
//#XmlElement
private String message;
public boolean isSuccess() {
return success;
}
public void setSuccess(boolean success) {
this.success = success;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
}
Edit
There is no stack trace, just this in the server output:
2013-11-13 21:26:20.976 WARN 5452 --- [nio-8888-exec-1]
o.s.web.servlet.PageNotFound :
Request method 'PUT' not supported
Here is the python as requested. And, I think the answer to the problem lies in "'allow': 'GET, HEAD'" in the response. So, how do I allow other methods? Maybe I need to think about an applicationContext?
path = '/jp5/rest/message/test'
method = 'PUT'
body = ''
target = urlparse(self.uri+path)
h = http.Http()
headers = {
'Accept': 'application/json',
'Content-Type': 'application/json; charset=UTF-8'
}
response, content = h.request(
target.geturl(),
method,
body,
headers)
print response
output from the print:
{'status': '405', 'content-length': '1045', 'content-language': 'en-US', 'server':
'Apache-Coyote/1.1', 'allow': 'GET, HEAD', 'date': 'Thu, 14 Nov 2013 02:26:20 GMT',
'content-type': 'text/html;charset=utf-8'}
I am starting the server like this:
#ComponentScan
#EnableAutoConfiguration
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
Thanks
Thanks for the pointers. The solution is to add a #ResponseBody:
public #ResponseBody testResult test()
{
return new testResult(true, "test");
}

Categories

Resources