java 47 lines · 7 steps

Polymorphic payment requests in Spring

A Spring REST endpoint deserializes and validates one of several payment types using a sealed interface and Jackson subtype resolution.

Explained by highlit
1@RestController
2@RequestMapping("/api/payments")
3public class PaymentController {
4 
5 private final PaymentProcessor processor;
6 
7 public PaymentController(PaymentProcessor processor) {
8 this.processor = processor;
9 }
10 
11 @PostMapping
12 public ResponseEntity<PaymentReceipt> submit(@Valid @RequestBody PaymentRequest request) {
13 PaymentReceipt receipt = processor.charge(request);
14 return ResponseEntity.status(HttpStatus.CREATED).body(receipt);
15 }
16 
17 @JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.EXISTING_PROPERTY, property = "method", visible = true)
18 @JsonSubTypes({
19 @JsonSubTypes.Type(value = CardPayment.class, name = "card"),
20 @JsonSubTypes.Type(value = BankTransferPayment.class, name = "bank_transfer"),
21 @JsonSubTypes.Type(value = WalletPayment.class, name = "wallet")
22 })
23 public sealed interface PaymentRequest permits CardPayment, BankTransferPayment, WalletPayment {
24 String method();
25 long amountCents();
26 }
27 
28 public record CardPayment(
29 @NotNull String method,
30 @Positive long amountCents,
31 @NotBlank @Pattern(regexp = "\\d{16}") String cardNumber,
32 @NotBlank String expiry) implements PaymentRequest {
33 }
34 
35 public record BankTransferPayment(
36 @NotNull String method,
37 @Positive long amountCents,
38 @NotBlank String iban,
39 @NotBlank String accountHolder) implements PaymentRequest {
40 }
41 
42 public record WalletPayment(
43 @NotNull String method,
44 @Positive long amountCents,
45 @NotBlank String walletId) implements PaymentRequest {
46 }
47}
01 / 01
STEP 01

Walkthrough

Space play step click any line
Three takeaways
  1. 1A sealed interface with Jackson subtypes lets one endpoint accept several concrete shapes while keeping the type set closed and exhaustive.
  2. 2Records make immutable DTOs concise, and validation annotations on their components enforce per-type rules automatically.
  3. 3Combining @Valid with polymorphic binding means each incoming payment method is validated against only its own constraints.

Related explainers

java
@Component
@Converter
public class EncryptedStringConverter implements AttributeConverter<String, String> {
 

Transparent column encryption in Spring & JPA

encryption aes-gcm jpa-converter
Advanced 10 steps
java
package com.acme.billing.config;
 
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.ConfigurationProperties;

Feature-flagged beans with Spring @ConditionalOnProperty

feature-flags conditional-beans strategy-pattern
Intermediate 5 steps
java
public static Map<String, String> parseCookieHeader(String header) {
    Map<String, String> cookies = new LinkedHashMap<>();
    if (header == null || header.isBlank()) {
        return cookies;

Parsing an HTTP Cookie header in Java

string-parsing http url-decoding
Intermediate 6 steps
java
public class TimedSocketReader {
 
    private static final int READ_TIMEOUT_MS = 5_000;
    private static final int CONNECT_TIMEOUT_MS = 3_000;

Reading a socket with connect and read timeouts

sockets timeouts io
Intermediate 8 steps
java
public final class EncodingDetector {
 
    public enum Encoding {
        UTF_8, UTF_16LE, UTF_16BE, UTF_32LE, UTF_32BE, ASCII, UNKNOWN

Detecting text encoding from raw bytes in Java

byte-manipulation encoding-detection bitwise-operations
Intermediate 8 steps
java
public final class ImportOrganizer {
 
    private static final Pattern IMPORT_LINE =
            Pattern.compile("^import\\s+(static\\s+)?([\\w.]+(?:\\.\\*)?)\\s*;\\s*$");

Sorting Java imports with a regex pass

regex sorting text-processing
Intermediate 8 steps

Share this explainer

Here's the card — post it anywhere.

Polymorphic payment requests in Spring — share card
Made with highlit — turn any snippet into a walkthrough like this in about a minute.
Explain your code