6

My question is almost 1:1 as this one. The only difference (and struggle) I have is that my "data container" has a collection of objects. It looks like this:

public class A {
    int plainFieldA;
    B fieldB;
    List<B> collectionB = new ArrayList<>();
}

public class B {
    int plainFieldB;
}

@Transactional(readOnly = true)
@GetMapping("")
public Entity getAll(A reqParam) {
    return getAll(reqParam);
}

Is it possible to define collectionB in params of the url http://localhost/api/test?plainFieldA=1 without creating a converter ? @GameSalutes correctly pointed out that since spring 4 we can do fieldB.plainFieldB=2 so the url will be: http://localhost/api/test?plainFieldA=1&fieldB.plainFieldB=2 but the question is can we do soemthing similar with collectionB without creating a converter ?

3
  • 1
    That's a good question. I would assume it's not possible, as there would be a problem of representation of values in a list. How would you represent them? collectionB[0].plainFieldB? And if you have 100 values? Don't forget that a Get mapping relies on the http GET method and there is a limit to the size of a QueryString. Commented Dec 12, 2019 at 10:10
  • I would choose to make a POST call for such a scenario because of the limit in character size for GET method Commented Dec 12, 2019 at 10:48
  • 1
    Looks like you are trying to implement search to search something based on different parameters. If you want to implement search based on different parameters then I will recommend you to use "Interpreter pattern" without worrying on additional handling. en.wikipedia.org/wiki/Interpreter_pattern Commented Dec 12, 2019 at 10:59

2 Answers 2

7
+200

Yes, you can make the request like this:

http://localhost/api/test?plainFieldA=1&fieldB.plainFieldB=2&collectionB[0].plainFieldB=9

Or encoding the request, for postman:

http://localhost/api/test?plainFieldA=1&fieldB.plainFieldB=2&collectionB%5B0%5D.plainFieldB=9

With two objects in request:

http://localhost/api/test?plainFieldA=1&fieldB.plainFieldB=2&collectionB%5B0%5D.plainFieldB=9&collectionB%5B1%5D.plainFieldB=11

The result with breakpoint in the IDE:

enter image description here

Sign up to request clarification or add additional context in comments.

4 Comments

Oh, well.. so long to my "I would assume it's not possible". I even literally wrote the syntax to use. :D Well deserved bounty, if the answer gets accepted!
That's perfect. Thank you. I clicked bounty button but it says "You may award your bounty in 14 hours" (and can't be transfered). So I will do that in 14 hours. Thank you.
Do you recomend POST over GET when it comes to searching by given criteria ?
Thank you! Yes, I recommend in this case POST over GET, in case you send more complex objects than a simple key/value. If one day you have a list with many elements, GET will bring you problems and also at design level you are sending an object.
0

Accepted answer works like a charm but I'm adding this answer as an alternative if someone reaches url size limit or some other reason.

Following this thread advice, here is how I've done.

  • Frontend: stringify your object than encode it in base64 for submission.
  • Backend: decode base64 string then convert the string json into desired object.

It isn't the best for debugging your API with postman but it is working as expected for me.

Original object: { page: 1, size: 5, filters: [{ field: "id", value: 1, comparison: "EQ" }

Encoded object: eyJwYWdlIjoxLCJzaXplIjo1LCJmaWx0ZXJzIjpbeyJmaWVsZCI6ImlkUGFyZW50IiwiY29tcGFyaXNvbiI6Ik5VTEwifV19

@GetMapping
fun list(@RequestParam search: String?): ResponseEntity<ListDTO> {
    val filter: SearchFilterDTO = decodeSearchFieldDTO(search)
    ...
}

private fun decodeSearchFieldDTO(search: String?): SearchFilterDTO {
    if (search.isNullOrEmpty()) return SearchFilterDTO()
    return Gson().fromJson(String(Base64.getDecoder().decode(search)), SearchFilterDTO::class.java)
}

And here the SearchFilterDTO and FilterDTO

class SearchFilterDTO(
    var currentPage: Int = 1,
    var pageSize: Int = 10,
    var sort: Sort? = null,
    var column: String? = null,
    var filters: List<FilterDTO> = ArrayList<FilterDTO>(),
    var paged: Boolean = true
)

class FilterDTO(
    var field: String,
    var value: Any,
    var comparison: Comparison
)

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.