Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Handle an empty query parameters with @Default #5515

Closed
ikhoon opened this issue Mar 18, 2024 · 6 comments · Fixed by #5534
Closed

Handle an empty query parameters with @Default #5515

ikhoon opened this issue Mar 18, 2024 · 6 comments · Fixed by #5534
Labels

Comments

@ikhoon
Copy link
Contributor

ikhoon commented Mar 18, 2024

Say we have an annotated service that uses @Default annotation to optionally bind query parameters.

class MyService {
    @Get("/list")
    public String list(@Default @Param Integer page) {
        ...
    }
}

As per the Javadoc of @Default, when a value is not specified for @Default, a non-existent parameter is converted into null. page is null if /list is the request path.

* When {@link Default} annotation exists but {@link Default#value()} is not specified, {@code null}
* value would be set if the parameter is not present in the request.

However, it does not work well if there is a parameter but no value. A NumberFormatException is raised when /list?page= is sent as the request path.

java.lang.NumberFormatException: For input string: ""
	at java.base/java.lang.NumberFormatException.forInputString(NumberFormatException.java:67)
	at java.base/java.lang.Integer.parseInt(Integer.java:671)
	at java.base/java.lang.Integer.valueOf(Integer.java:988)
	at com.linecorp.armeria.internal.server.annotation.AnnotatedServiceTypeUtil.stringToType(AnnotatedServiceTypeUtil.java:177)
	at com.linecorp.armeria.internal.server.annotation.AnnotatedValueResolver.convert(AnnotatedValueResolver.java:1021)

It would be better to solve this problem as follows the value of the parameter is empty.

  • Inject an empty string ("") if the type of page is String.
  • Inject a null value if the type of page is not String such as Integer, Boolean and so on.
@ikhoon ikhoon added the defect label Mar 18, 2024
@ikhoon
Copy link
Contributor Author

ikhoon commented Mar 18, 2024

In addition to the bugfix, we also need to improve the error message when an incorrect request is made so that users can easily identify the problem.

@facewise
Copy link
Contributor

@ikhoon
Hello. Can I pick up this issue?

@ikhoon
Copy link
Contributor Author

ikhoon commented Mar 21, 2024

Yes, please. 😀

@facewise
Copy link
Contributor

facewise commented Mar 21, 2024

@ikhoon
What if the type of parameter is primitive such as int, long?
These don't allow null values.

class MyService {
    @Get("/list")
    public String list(@Default @Param int page) {
        ...
    }
}

and the parameter exists but the value has not been present like
/list?page=

In this case, which response do you prefer?

@facewise
Copy link
Contributor

@ikhoon

Plus, in terms of handling empty query parameters, I am considering couple of cases like below:

Case 1

Say service is like:

class MyService {
    @Get("/list")
    public String list(@Default("1") @Param List<Integer> params) {
        ...
    }
}

But the request is sent like /list?params=.

Then which action would be processed?

  1. Inject null to params
  2. Inject [1] to params
  3. Throw an exception

Case 2

If service is like

class MyService {
    @Get("/list")
    public String list(@Default @Param List<Integer> params) {
        ...
    }
}

and the request is sent like /list?params=.

Then which action would be processed?

  1. Inject null to params
  2. Inject [null] to params
  3. Throw an exception

Case 3

If service is like

class MyService {
    @Get("/list")
    public String list(@Default @Param List<String> params) {
        ...
    }
}

and the request is sent like /list?params=.

Then which action would be processed?

  1. Inject null to params
  2. Inject [""] to params
  3. Inject [null] to params
  4. Throw an exception

Please give me your opinion for enhancement. Thank you.

@ikhoon
Copy link
Contributor Author

ikhoon commented Mar 25, 2024

What if the type of parameter is primitive such as int, long?
In this case, which response do you prefer?

In that case, IllegalArgumentException might be good. IllegalArgumentException will be translated into a 404 Bad request by the default error handler.

Case 1

  1. that injects [1] to params looks good to me.

Case 2 and Case 3

I prefer to inject [] an empty list.

Thanks for your thorough analysis. 👍

jrhee17 added a commit that referenced this issue Apr 4, 2024
Motivation:

Say we have an annotated service that uses `@Default `annotation to
optionally bind query parameters.

```java
class MyService {
    @get("/list")
    public String list(@default @param Integer page) {
        ...
    }
}
```

It does not inject `null` if there is a parameter but no value. A
NumberFormatException is raised when `/list?page=` is sent as the
request path.

It would be better to solve this problem as follows the value of the
parameter is empty.

Modifications:

- Logger will warn that the parameter value is not present (It may be
intended, such as sending an empty string as the parameter)
- Inject an empty string `""` if the type of the parameter is `String`
- Inject `null` if the type of the parameter is not `String` such as
`Integer`, `Boolean` and so on
- Throw an `IllegalArgumentException` if the type of the parameter is
primitive type
- Inject an empty list `[]` if the type of the parameter is `List` or
`Set`

Result:

- Closes #5515.

---------

Co-authored-by: jrhee17 <guins_j@guins.org>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
2 participants