Class Mappers

java.lang.Object
com.codename1.mapping.Mappers

public final class Mappers extends Object

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 a new cn1app.MapperBootstrap(); into the per-build application stub before Display.init. That constructor references every generated mapper, triggering their static initializers.
  • JavaSE simulator + desktop -- JavaSEPort#postInit calls Class.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.

  • Method Details

    • register

      public static <T> void register(Mapper<T> mapper)
      Installs 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)
      Looks up the mapper for type (by type.getName()) or null when none is registered.
    • toJson

      public static String toJson(Object instance)
      Serializes 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)
      Inverse of #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)
      Parses JSON read from a Reader (file, network response, ...) without fully buffering it into a String first.
    • toXml

      public static String toXml(Object instance)
      Serializes instance to XML.
    • fromXml

      public static <T> T fromXml(String xml, Class<T> type)
      Inverse of #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)
      Parses XML read from a 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.