sealed: add release-level and Jackson 3.2.3 transcripts
09 shows which language level each sealed feature needs; 10 runs the Payment model through Jackson 3 (jars fetched and sha1-checked, not committed). Co-Authored-By: Claude Sonnet 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01TF9JWFvJSNm6HVzswzZU5a
This commit is contained in:
@@ -0,0 +1 @@
|
||||
lib/
|
||||
@@ -0,0 +1,25 @@
|
||||
import com.fasterxml.jackson.annotation.JsonSubTypes;
|
||||
import com.fasterxml.jackson.annotation.JsonTypeInfo;
|
||||
import tools.jackson.databind.json.JsonMapper;
|
||||
|
||||
public class JsonForgotten {
|
||||
// Wallet is a permitted subtype, and the compiler is happy, but nobody told Jackson about it.
|
||||
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "type")
|
||||
@JsonSubTypes({
|
||||
@JsonSubTypes.Type(value = Card.class, name = "card"),
|
||||
@JsonSubTypes.Type(value = Upi.class, name = "upi")})
|
||||
sealed interface Payment permits Card, Upi, Wallet {}
|
||||
record Card(long amount) implements Payment {}
|
||||
record Upi(long amount) implements Payment {}
|
||||
record Wallet(long amount) implements Payment {}
|
||||
|
||||
public static void main(String[] args) {
|
||||
JsonMapper mapper = JsonMapper.builder().build();
|
||||
System.out.println("write : " + mapper.writeValueAsString(new Wallet(500)));
|
||||
try {
|
||||
mapper.readValue("{\"type\":\"wallet\",\"amount\":500}", Payment.class);
|
||||
} catch (Exception e) {
|
||||
System.out.println("read : " + e.getClass().getSimpleName() + ": " + e.getMessage().lines().findFirst().orElse(""));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
import com.fasterxml.jackson.annotation.JsonTypeInfo;
|
||||
import tools.jackson.databind.json.JsonMapper;
|
||||
|
||||
public class JsonNoSubTypes {
|
||||
// Only @JsonTypeInfo, no @JsonSubTypes. Does Jackson find the permitted subclasses by itself?
|
||||
@JsonTypeInfo(use = JsonTypeInfo.Id.SIMPLE_NAME, property = "type")
|
||||
sealed interface Payment permits Card, Upi {}
|
||||
record Card(long amount) implements Payment {}
|
||||
record Upi(long amount) implements Payment {}
|
||||
|
||||
// Control: the same shape without the word sealed.
|
||||
@JsonTypeInfo(use = JsonTypeInfo.Id.SIMPLE_NAME, property = "type")
|
||||
interface OpenPayment {}
|
||||
record OpenCard(long amount) implements OpenPayment {}
|
||||
|
||||
static void tryRead(JsonMapper m, String label, String json, Class<?> type) {
|
||||
try {
|
||||
System.out.println(label + ": " + m.readValue(json, type));
|
||||
} catch (Exception e) {
|
||||
System.out.println(label + ": " + e.getClass().getSimpleName() + ": " + e.getMessage().lines().findFirst().orElse(""));
|
||||
}
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
JsonMapper m = JsonMapper.builder().build();
|
||||
System.out.println("write : " + m.writeValueAsString(new Card(500)));
|
||||
tryRead(m, "sealed, Card ", "{\"type\":\"Card\",\"amount\":500}", Payment.class);
|
||||
tryRead(m, "sealed, Upi ", "{\"type\":\"Upi\",\"amount\":500}", Payment.class);
|
||||
tryRead(m, "sealed, Cheque", "{\"type\":\"Cheque\",\"amount\":500}", Payment.class);
|
||||
tryRead(m, "plain, OpenCard", "{\"type\":\"OpenCard\",\"amount\":500}", OpenPayment.class);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
import com.fasterxml.jackson.annotation.JsonSubTypes;
|
||||
import com.fasterxml.jackson.annotation.JsonTypeInfo;
|
||||
import tools.jackson.databind.json.JsonMapper;
|
||||
|
||||
public class JsonPayment {
|
||||
// Two annotations tell Jackson which JSON field names the type, and which class each name means.
|
||||
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "type")
|
||||
@JsonSubTypes({
|
||||
@JsonSubTypes.Type(value = Card.class, name = "card"),
|
||||
@JsonSubTypes.Type(value = Upi.class, name = "upi"),
|
||||
@JsonSubTypes.Type(value = NetBanking.class, name = "netbanking")})
|
||||
sealed interface Payment permits Card, Upi, NetBanking {}
|
||||
record Card(String last4, long amount) implements Payment {}
|
||||
record Upi(String vpa, long amount) implements Payment {}
|
||||
record NetBanking(String bank, long amount) implements Payment {}
|
||||
|
||||
static long fee(Payment p) {
|
||||
return switch (p) {
|
||||
case Card(String last4, long amount) -> amount * 2 / 100;
|
||||
case Upi(String vpa, long amount) -> 0;
|
||||
case NetBanking(String bank, long amount) -> 15;
|
||||
};
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
JsonMapper mapper = JsonMapper.builder().build();
|
||||
Payment[] all = { new Card("4242", 500), new Upi("ankur@bank", 500), new NetBanking("HDFC", 500) };
|
||||
for (Payment p : all) {
|
||||
String json = mapper.writeValueAsString(p);
|
||||
Payment back = mapper.readValue(json, Payment.class);
|
||||
System.out.println(json + " -> " + back + " equal=" + back.equals(p) + " fee=" + fee(back));
|
||||
}
|
||||
try {
|
||||
mapper.readValue("{\"type\":\"cheque\",\"amount\":500}", Payment.class);
|
||||
} catch (Exception e) {
|
||||
System.out.println("unknown type: " + e.getClass().getSimpleName() + ": " + e.getMessage().lines().findFirst().orElse(""));
|
||||
}
|
||||
}
|
||||
}
|
||||
Executable
+13
@@ -0,0 +1,13 @@
|
||||
#!/usr/bin/env bash
|
||||
# Downloads the three Jackson jars from Maven Central into ./lib and checks each against the published .sha1
|
||||
set -euo pipefail
|
||||
cd "$(dirname "$0")"; mkdir -p lib
|
||||
M=https://repo1.maven.org/maven2
|
||||
for a in tools/jackson/core/jackson-databind/3.2.3/jackson-databind-3.2.3 \
|
||||
tools/jackson/core/jackson-core/3.2.3/jackson-core-3.2.3 \
|
||||
com/fasterxml/jackson/core/jackson-annotations/2.22/jackson-annotations-2.22; do
|
||||
f="lib/$(basename "$a").jar"
|
||||
[ -f "$f" ] || curl -sfL -o "$f" "$M/$a.jar"
|
||||
want="$(curl -sfL "$M/$a.jar.sha1" | cut -d' ' -f1)"; got="$(sha1sum "$f" | cut -d' ' -f1)"
|
||||
[ "$want" = "$got" ] && echo "ok $f $got" || { echo "SHA1 MISMATCH $f"; exit 1; }
|
||||
done
|
||||
Reference in New Issue
Block a user