6

I work with Java/ Spring MVC RESTful app and get 400 HTTP status error while doing a POST request. The @RestController method is provided,

@RequestMapping(value = "/generateAddress", method = RequestMethod.POST)
    public ResponseEntity<WalletInfoWrapper> generateAddress(@RequestParam("walletName") String walletName,
                                                             @RequestParam("currencyName") String currencyName) {

        logger.info("walletName {} and currencyName {}", walletName, currencyName);

        // return if the wallet name or the currency is null
        if (Objects.isNull(walletName) || Objects.isNull(currencyName)) {
            return new ResponseEntity<WalletInfoWrapper>(HttpStatus.NOT_ACCEPTABLE);
        }

        WalletInfo walletInfo = walletService.generateAddress(walletName, currencyName);

        if (Objects.isNull(walletInfo)) {
            return new ResponseEntity<WalletInfoWrapper>(HttpStatus.NOT_ACCEPTABLE);
        }

        WalletInfoWrapper walletInfoWrapper = new WalletInfoWrapper();
        walletInfoWrapper.setName(walletInfo.getName());

        return new ResponseEntity<WalletInfoWrapper>(walletInfoWrapper, HttpStatus.CREATED);
    }

The POST request in the Postman provided below,

enter image description here

The error message informs, Required String parameter 'walletName' is not present

enter image description here

I can also provide the code for the services and the dataase layers for observing the drop-down operations. What is the issue here?

UPDATE

I updated the Postman request like this and still having the same error,

enter image description here

UPDATE 1

I still have the same issue,

I POST with the data,

{"walletName":"puut","currencyName":"Bitcoin"}

The code is provided below,

@RequestMapping(value = "/generateAddress", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
    public ResponseEntity<WalletInfoWrapper> generateAddress(@RequestBody WalletWithMoneyRequest walletWithMoneyRequest) {

        String walletName = walletWithMoneyRequest.getWalletName();

        String currencyName = walletWithMoneyRequest.getCurrencyName();

        logger.info("walletName {} and currencyName {}", walletName, currencyName);

        // return if the wallet name or the currency is null
        if (Objects.isNull(walletName) || Objects.isNull(currencyName)) {
            return new ResponseEntity<WalletInfoWrapper>(HttpStatus.NOT_ACCEPTABLE);
        }

        WalletInfo walletInfo = walletService.generateAddress(walletName, currencyName);

        if (Objects.isNull(walletInfo)) {
            return new ResponseEntity<WalletInfoWrapper>(HttpStatus.NOT_ACCEPTABLE);
        }

        WalletInfoWrapper walletInfoWrapper = new WalletInfoWrapper();
        walletInfoWrapper.setName(walletInfo.getName());

        return new ResponseEntity<WalletInfoWrapper>(walletInfoWrapper, HttpStatus.CREATED);
    }

The POJO is provided,

private class WalletWithMoneyRequest {

        String walletName;

        String currencyName;

        public WalletWithMoneyRequest(String walletName, String currencyName) {
            this.walletName = walletName;
            this.currencyName = currencyName;
        }

        public WalletWithMoneyRequest() {
        }

        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;
        }
    }

This is the error message,

enter image description here

Here ia the Tomcat server info,

org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver: 08/19/2017 19:45:55 - Failed to read HTTP message: org.springframework.http.converter.HttpMessageNotReadableException: JSON parse error: Cannot construct instance of `mobi.puut.controllers.WalletRestController$WalletWithMoneyRequest` (although at least one Creator exists): can only instantiate non-static inner class by using default, no-argument constructor; nested exception is com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot construct instance of `mobi.puut.controllers.WalletRestController$WalletWithMoneyRequest` (although at least one Creator exists): can only instantiate non-static inner class by using default, no-argument constructor
 at [Source: (PushbackInputStream); line: 1, column: 2]

Tomcat Localhost log

enter image description here

Tomcat Catalina log enter image description here

Arefe
  • 11,321
  • 18
  • 114
  • 168
  • 3
    It seems like you are sending a JSON string as a parameter, but that's not what your controller expects. Or is that just how it looks in Postman? – tima Aug 19 '17 at 13:08
  • How to make the controller understand it? – Arefe Aug 19 '17 at 13:09
  • Note: RESTful requests usually accept GET or POST parameters and return JSON. – Powerlord Aug 19 '17 at 13:39
  • @Powerlord, the ```@ResponseBody``` is implicit on methods of ```@RestController``` annotated classes. I was unaware of the ```@RequestBody``` implicit annotation. – zerpsed Aug 19 '17 at 13:45
  • 1
    @Artin, do you have any output from your server's console or log that might indicate why your server doesn't like your request? – zerpsed Aug 19 '17 at 13:53
  • 1
    Yes, I do have one message, have a look in the updated post – Arefe Aug 19 '17 at 14:02
  • 1
    Saw the output. Good. Try making your class WalletWithMoneyRequest public instead of private. – zerpsed Aug 19 '17 at 14:06
  • 1
    Making it `public` doesn't help and still I get `HTTP status of 400`. Though I think we have cornered the issue with the error message provided in the question. – Arefe Aug 19 '17 at 14:06
  • Make WalletWithMoneyRequest its own outer class. Jackson seems to be harder to use when marshaling json to an inner class. see: https://stackoverflow.com/questions/17289964/jackson-json-type-mapping-inner-class . This is also worth a read: http://www.cowtowncoder.com/blog/archives/2010/08/entry_411.html copied from linked answer. – zerpsed Aug 19 '17 at 14:15

5 Answers5

3

Edit

In your Postman request, instead of sending JSON, send the values as x-www-form-urlencoded.

enter image description here

tima
  • 1,498
  • 4
  • 20
  • 28
2

Your controller is expecting 2 request parameters that normally look like this: /someurl?walletName=my-wallets-name&currencyName=dollars.

You're sending a json string in the post body, but no formal parameters. You need to update either your POST, or your controller to make the two ends agree. I think you probably want to replace the two @RequestParam annotated Strings, with a Java pojo that has two String members: walletName and currencyName, drop that pojo in your request method as an argument and precede it with the annotation @RequestBody. This will match your json post.

To have your controller accept the post with JSON in the body edit it like this:

@RequestMapping(value = "/generateAddress", method = RequestMethod.POST)
public ResponseEntity<WalletInfoWrapper> generateAddress(@RequestBody
    WalletWithMoneyRequest myJsonRequestComingIn) {
    logger.info("walletName {} and currencyName {}", myJsonRequestComingIn.getWalletName(), myJsonRequestComingIn.getCurrencyName());

And your pojo

public class WalletWithMoneyRequest{ 

    private String walletName;
    private String currencyName;

    //getters and setters down here. 
zerpsed
  • 495
  • 8
  • 15
  • I avoided providing an explicit answer, so that if you're trying to learn something new, you have the opportunity to figure things out. Let me know and I'll update with a code example, if you need it. – zerpsed Aug 19 '17 at 13:17
  • The code sample will be helpful with the answer. if you do so, please, provide both of the ways `(update either the POST, or the controller)` to execute the operation correctly. – Arefe Aug 19 '17 at 13:21
  • 1
    Have a look at the answer I have posted. I accepted your though – Arefe Aug 19 '17 at 14:35
  • @Artin, great. Glad you got it. – zerpsed Aug 19 '17 at 15:10
1

To elaborate on zerpsed's answer.

Change the signature to:

public ResponseEntity<WalletInfoWrapper> generateAddress(@ResponseBody WalletPOJO walletCurrency)

Where the WalletPOJO has the two fields walletName and currencyName

1

I believe the issue is solved for now. I have used a POJO as suggested with the @RequestBody parameter in the RESTful method. The catch here is I need to make the POJO out of the class (in the same file though) and later, put in the entity directory as an entity.

class WalletWithMoneyRequest {

    String walletName;

    String currencyName;

    public WalletWithMoneyRequest(String walletName, String currencyName) {
        this.walletName = walletName;
        this.currencyName = currencyName;
    }

    public WalletWithMoneyRequest() {
    }

    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;
    }
}

The main issue is believe was an error in the HQL,

enter image description here

I wrote currency =: currency where it should be currency = :currency

I still can't have the data in the database as I will need to modify the method in the database layer.

Arefe
  • 11,321
  • 18
  • 114
  • 168
0

En POSTMAN set variables in params enter image description here

RealHowTo
  • 34,977
  • 11
  • 70
  • 85