part4custom: add E06 (ValueDeserializer direct) and E07 (mix-in on a record), fix run-all.sh exit-code detection through the grep filter (post #50)
This commit is contained in:
@@ -0,0 +1,65 @@
|
||||
package com.ankurm.jackson3.part4custom;
|
||||
|
||||
import tools.jackson.core.JsonParser;
|
||||
import tools.jackson.databind.DeserializationContext;
|
||||
import tools.jackson.databind.ValueDeserializer;
|
||||
import tools.jackson.databind.json.JsonMapper;
|
||||
import tools.jackson.databind.module.SimpleModule;
|
||||
|
||||
/**
|
||||
* BEYOND THE POST — the deserialising half of E05ValueSerializerDirect.
|
||||
*
|
||||
* E05 showed ValueSerializer<T> written directly, without the StdSerializer detour.
|
||||
* This is the other half: ValueDeserializer<T> written directly, without StdDeserializer.
|
||||
* Together they round-trip UserId as a bare JSON string ("u-42") instead of the
|
||||
* structural {"value":"u-42"} a record would otherwise produce.
|
||||
*/
|
||||
public class E06ValueDeserializerDirect {
|
||||
|
||||
public record UserId(String value) { }
|
||||
|
||||
static class UserIdSerializer extends tools.jackson.databind.ValueSerializer<UserId> {
|
||||
@Override
|
||||
public void serialize(UserId id, tools.jackson.core.JsonGenerator gen,
|
||||
tools.jackson.databind.SerializationContext ctxt) {
|
||||
gen.writeString(id.value());
|
||||
}
|
||||
}
|
||||
|
||||
/** Reads the bare JSON string straight back into the wrapper type. */
|
||||
static class UserIdDeserializer extends ValueDeserializer<UserId> {
|
||||
@Override
|
||||
public UserId deserialize(JsonParser p, DeserializationContext ctxt) {
|
||||
return new UserId(p.getString());
|
||||
}
|
||||
}
|
||||
|
||||
public record Ticket(UserId assignee, String title) { }
|
||||
|
||||
public static void main(String[] args) {
|
||||
SimpleModule module = new SimpleModule("UserIdModule");
|
||||
module.addSerializer(UserId.class, new UserIdSerializer());
|
||||
module.addDeserializer(UserId.class, new UserIdDeserializer());
|
||||
|
||||
JsonMapper mapper = JsonMapper.builder().addModule(module).build();
|
||||
|
||||
Ticket original = new Ticket(new UserId("u-42"), "Fix build");
|
||||
String json = mapper.writeValueAsString(original);
|
||||
System.out.println("serialised : " + json);
|
||||
|
||||
Ticket restored = mapper.readValue(json, Ticket.class);
|
||||
System.out.println("round-trip : " + restored);
|
||||
System.out.println("equal : " + original.equals(restored));
|
||||
|
||||
// Without the module, Jackson can't turn a bare JSON string "u-42" into a
|
||||
// one-component record - it expects {"value":"u-42"} and this throws.
|
||||
JsonMapper plain = JsonMapper.builder().build();
|
||||
try {
|
||||
plain.readValue("{\"assignee\":\"u-42\",\"title\":\"Fix build\"}", Ticket.class);
|
||||
System.out.println("no module : (unexpectedly succeeded)");
|
||||
} catch (Exception e) {
|
||||
System.out.println("no module : " + e.getClass().getSimpleName()
|
||||
+ " - " + e.getMessage().lines().findFirst().orElse(""));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
package com.ankurm.jackson3.part4custom;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import tools.jackson.databind.json.JsonMapper;
|
||||
|
||||
/**
|
||||
* BEYOND THE POST — does addMixIn() still work when the third-party type is a
|
||||
* record, not a field-and-getter class like E04's Address?
|
||||
*
|
||||
* A record's "properties" are its canonical accessor methods (postalCode(), not
|
||||
* getPostalCode()), so a mixin has to declare methods with those exact names for
|
||||
* Jackson's annotation-introspection merge to find them. Run this before assuming
|
||||
* either way - the answer below was obtained by actually running it, not inferred
|
||||
* from how E04's field-based mixin behaves.
|
||||
*/
|
||||
public class E07MixinOnRecord {
|
||||
|
||||
/** Stand-in for a third-party record type whose source you cannot modify. */
|
||||
public record AddressRecord(String street, String city, String postalCode,
|
||||
String internalTrackingCode) { }
|
||||
|
||||
/** Mix-in for AddressRecord: method signatures, not fields, to match a record's accessors. */
|
||||
public interface AddressRecordMixin {
|
||||
@JsonIgnore
|
||||
String internalTrackingCode();
|
||||
|
||||
@JsonProperty("zip")
|
||||
String postalCode();
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
AddressRecord address = new AddressRecord(
|
||||
"123 Main St", "Springfield", "12345", "INTERNAL-X99");
|
||||
|
||||
JsonMapper withMixin = JsonMapper.builder()
|
||||
.addMixIn(AddressRecord.class, AddressRecordMixin.class)
|
||||
.build();
|
||||
System.out.println("with mixin : " + withMixin.writeValueAsString(address));
|
||||
|
||||
JsonMapper withoutMixin = JsonMapper.builder().build();
|
||||
System.out.println("without mixin: " + withoutMixin.writeValueAsString(address));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user