DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

Related

  • Scalable Support Request Analysis Using Embeddings, HDBSCAN, and Tiny LLMs
  • KV Cache Implementation Inside vLLM
  • When Retries Become a Denial-of-Wallet
  • The Bill You Didn't See Coming

Trending

  • Lift-and-Shift vs. Modernize: A Decision Framework for Enterprise Workloads
  • Exploring A Few Java 25 Language Enhancements
  • SEO Writing 101: A Simple Guide to Getting Found
  • The Rise of Agentic SRE: Humans, Agents, and Reliability

Micronaut Mastery: Binding Request Parameters to POJO

We take a quick look at how Java developers can work with POJOs in their microservices via the Micronaut framework.

By 
Hubert Klein Ikkink user avatar
Hubert Klein Ikkink
·
May. 03, 19 · Tutorial
Likes (3)
Comment
Save
Tweet
Share
17.1K Views

Join the DZone community and get the full member experience.

Join For Free

Micronaut supports the RFC-6570 URI template specification to define URI variables in a path definition. The path definition can be a value of the @Controller annotation or any of the routing annotations for example @Get or @Post. We can define a path variable as {?binding*} to support binding of request parameters to all properties of an object type that is defined as method argument with the name binding. We can even use the Bean Validation API (JSR380) to validate the values of the request parameters if we add an implementation of this API to our class path.

In the following example controller, we have the method items with the method argument sorting of type Sorting. We want to map the request parameters ascending and field to the properties of the Sorting object. We only have the use the path variable {?sorting*} to make this happen. We also add the dependency io.micronaut.configuration:micronaut-hibernate-validator to our class path. If we use Gradle we can add compile("io.micronaut.configuration:micronaut-hibernate-validator") to our build file.

package mrhaki;

import io.micronaut.http.annotation.Controller;
import io.micronaut.http.annotation.Get;
import io.micronaut.validation.Validated;

import javax.validation.Valid;
import javax.validation.constraints.Pattern;
import java.util.List;

@Controller("/sample")
@Validated // Enable validation of Sorting properties.
public class SampleController {

    private final SampleComponent sampleRepository;

    public SampleController(final SampleComponent sampleRepository) {
        this.sampleRepository = sampleRepository;
    }

    // Using the syntax {?sorting*} we can assign request parameters
    // to a POJO, where the request parameter name matches a property
    // name in the POJO. The name 'must match the argument  
    // name of our method, which is 'sorting' in our example.
    // The properties of the POJO can use the Validation API to 
    // define constraints and those will be validated if we use
    // @Valid for the method argument and @Validated at the class level.
    @Get("/{?sorting*}")
    public List<Item> items(@Valid final Sorting sorting) {
        return sampleRepository.allItems(sorting.getField(), sorting.getDirection());
    }

    private static class Sorting {

        private boolean ascending = true;

        @Pattern(regexp = "name|city", message = "Field must have value 'name' or 'city'.")
        private String field = "name";

        private String getDirection() {
            return ascending ? "ASC" : "DESC";
        }

        public boolean isAscending() {
            return ascending;
        }

        public void setAscending(final boolean ascending) {
            this.ascending = ascending;
        }

        public String getField() {
            return field;
        }

        public void setField(final String field) {
            this.field = field;
        }
    }
}

Let's write a test to check that the binding of the request parameters happens correctly. We use the Micronaut test support for Spock so we can use the @Micronaut and @MockBean annotations. We add a dependency on io.micronaut:micronaut-test-spock to our build, which is testCompile("io.micronaut.test:micronaut-test-spock:1.0.2") if we use a Gradle build.

package mrhaki

import io.micronaut.http.HttpStatus
import io.micronaut.http.client.RxHttpClient
import io.micronaut.http.client.annotation.Client
import io.micronaut.http.client.exceptions.HttpClientResponseException
import io.micronaut.http.uri.UriTemplate
import io.micronaut.test.annotation.MicronautTest
import io.micronaut.test.annotation.MockBean
import spock.lang.Specification

import javax.inject.Inject

@MicronautTest
class SampleControllerSpec extends Specification {

    // Client to test the /sample endpoint.
    @Inject
    @Client("/sample")
    RxHttpClient httpClient

    // Will inject mock created by sampleRepository method.
    @Inject
    SampleComponent sampleRepository

    // Mock for SampleRepository to check method is
    // invoked with correct arguments.
    @MockBean(SampleRepository)
    SampleComponent sampleRepository() {
        return Mock(SampleComponent)
    }

    void "sorting request parameters are bound to Sorting object"() {
        given:
        // UriTemplate to expand field and ascending request parameters with values.
        // E.g. ?field=name&expanding=false.
        final requestURI = new UriTemplate("/{?field,ascending}").expand(field: paramField, ascending: paramAscending)

        when:
        httpClient.toBlocking().exchange(requestURI)

        then:
        1 * sampleRepository.allItems(sortField, sortDirection) >> []

        where:
        paramField | paramAscending | sortField | sortDirection
        null       | null           | "name"    | "ASC"
        null       | false          | "name"    | "DESC"
        null       | true           | "name"    | "ASC"
        "city"     | false          | "city"    | "DESC"
        "city"     | true           | "city"    | "ASC"
        "name"     | false          | "name"    | "DESC"
        "name"     | true           | "name"    | "ASC"
    }

    void "invalid sorting field should give error response"() {
        given:
        final requestURI = new UriTemplate("/{?field,ascending}").expand(field: "invalid")

        when:
        httpClient.toBlocking().exchange(requestURI)

        then:
        final HttpClientResponseException clientResponseException = thrown()
        clientResponseException.response.status == HttpStatus.BAD_REQUEST
        clientResponseException.message == "sorting.field: Field must have value 'name' or 'city'."
    }
}

Written with Micronaut 1.0.4.

Requests Binding (linguistics)

Published at DZone with permission of Hubert Klein Ikkink. See the original article here.

Opinions expressed by DZone contributors are their own.

Related

  • Scalable Support Request Analysis Using Embeddings, HDBSCAN, and Tiny LLMs
  • KV Cache Implementation Inside vLLM
  • When Retries Become a Denial-of-Wallet
  • The Bill You Didn't See Coming

Partner Resources

×

Comments

The likes didn't load as expected. Please refresh the page and try again.

  • RSS
  • X
  • Facebook

ABOUT US

  • About DZone
  • Support and feedback
  • Community research

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 215
  • Nashville, TN 37211
  • [email protected]

Let's be friends:

  • RSS
  • X
  • Facebook