public final class Mappers
- Object
- Mappers
Public entry point for the build-time JSON / XML mapping framework.
@Mapped classes get a generated mapper at build time. The generated
mapper’s static initializer self-registers with this registry. The
registry stays empty until something triggers each generated class’s
<clinit>:
- iOS / Android – the build server probes the project zip for
cn1app.MapperBootstrap, and when present splices anew cn1app.MapperBootstrap();into the per-build application stub beforeDisplay.init. That constructor references every generated mapper, triggering their static initializers. - JavaSE simulator + desktop –
JavaSEPort#postInitcallsClass.forName("cn1app.MapperBootstrap")so the registry is populated on the same boundary. Classloading is the legitimate path here: JavaSE runs unobfuscated. - Unit tests / manual init – application code can call
Mappers.register(...)directly to install a hand-written mapper for a class the build can’t annotate.
Typical use after init:
String json = Mappers.toJson(user);
User u = Mappers.fromJson(json, User.class);
String xml = Mappers.toXml(user);
User u = Mappers.fromXml(xml, User.class);
The registry is keyed on getClass().getName() so it survives ParparVM
rename and R8 obfuscation: both the registration site and the lookup
site see the same renamed name within a single execution. The map keys
are never persisted, so the renaming has no observable effect on
behavior.
Methods
Inherited methods
Method details
register
public static <T> void register(Mapper<T> mapper)mapper under mapper.type().getName(). The generated
per-class mapper’s static initializer calls this; hand-written
mappers for classes outside the build’s annotation scan call it
explicitly.get
public static <T> Mapper<T> get(Class<T> type)type (by type.getName()) or null when
none is registered.toJson
public static String toJson(Object instance)instance to JSON. Throws IllegalStateException when
no mapper is registered for its concrete class; that always points
at a missing @Mapped annotation or a build that ran without the
process-annotations Mojo.fromJson
public static <T> T fromJson(String json, Class<T> type)#toJson. Parses the JSON text and hands the resulting
Map to the registered mapper.fromJson
public static <T> T fromJson(Reader json, Class<T> type)Reader (file, network response, …) without
fully buffering it into a String first.toXml
public static String toXml(Object instance)instance to XML.fromXml
public static <T> T fromXml(String xml, Class<T> type)#toXml. Parses the XML text and hands the resulting
Element to the registered mapper.fromXml
public static <T> T fromXml(Reader xml, Class<T> type)Reader without fully buffering it first.appendJsonValue
public static void appendJsonValue(StringBuilder out, Object value)Appends any value a generated codec can hold, producing exactly what the map path would.
Public because generated toJson methods call it for the property kinds
they cannot render inline – a nested mapped object, a Property’s value,
a list element. A nested object goes through ITS mapper, taking that
mapper’s Mapper.Direct route when it offers one, so nesting stays free
of intermediate maps all the way down.
Conversions match Mapper#toMap exactly, and must keep matching: a date
becomes its millisecond value and an enum its name(), because that is
what the map path puts in the map before the writer ever sees it.
appendJson
public static void appendJson(Object instance, StringBuilder out)Appends instance as a JSON object using its registered mapper, taking
the Mapper.Direct route when that mapper offers one.
Unlike #toJson(Object) this appends rather than returning a String, so
nesting does not build one String per level. An unmapped value falls back
to its toString, which is what Mapper#toMap does for the same case
rather than failing the whole document.
appendJsonRaw
public static void appendJsonRaw(StringBuilder out, Object value)Appends value exactly as JSONWriter would render it if it had been put
into the map that Mapper#toMap builds.
This is deliberately NOT #appendJsonValue: that one is smarter, turning a
Date into epoch milliseconds and a mapped object into nested JSON. Where a
generated mapper is reproducing what the map path stored RAW – a Property
value is the case that matters – being smarter is being different, and
Mapper.Direct promises identical output rather than better output.
appendJsonUsing
public static void appendJsonUsing(Mapper<?> mapper, Object instance, StringBuilder out)Appends instance through the mapper the CALLER names, rather than the one
registered for the instance’s runtime class.
The distinction is polymorphism. A field declared Base holding an instance
of an unmapped subclass finds no mapper by runtime class, and
#appendJson(Object, StringBuilder) then falls back to the quoted
toString. Mapper#toMap looks the mapper up by the DECLARED type and
serialises the subclass as an object, so a generated mapper reproducing the
map path has to ask the same question. Mirrors what the map path does with a
null mapper too: the raw value, which renders as its quoted toString.
appendJsonString
public static void appendJsonString(StringBuilder sb, String s)Appends s as an escaped JSON string, or null.
Public because GENERATED mappers call it: a direct writer has to escape exactly the way the map path does, and the only way to guarantee that is for both to use this method rather than each having its own copy.