Class TypeEncoder


  • final class TypeEncoder
    extends java.lang.Object
    Encodes types so they can later be decoded to incorporate imports.

    The idea is that types that appear in generated source code use encode(javax.lang.model.type.TypeMirror), which will spell out a type like java.util.List<? extends java.lang.Number>, except that wherever a class name appears it is replaced by a special token. So the spelling might actually be `java.util.List`<? extends `java.lang.Number`>. Then once the entire class has been generated, #decode scans for these tokens to determine what classes need to be imported, and replaces the tokens with the correct spelling given the imports. So here, java.util.List would be imported, and the final spelling would be List<? extends Number> (knowing that Number is implicitly imported). The special token `import` marks where the imports should be, and decode(java.lang.String, javax.annotation.processing.ProcessingEnvironment, java.lang.String, javax.lang.model.type.TypeMirror) replaces it with the correct list of imports.

    The funky syntax for type annotations on qualified type names requires an adjustment to this scheme. `«java.util.Map` stands for java.util. and `»java.util.Map` stands for Map. If java.util.Map is imported, then `«java.util.Map` will eventually be empty, but if java.util.Map is not imported (perhaps because there is another Map in scope) then `«java.util.Map` will be java.util.. The end result is that the code can contain `«java.util.Map`@`javax.annotation.Nullable` `»java.util.Map`. That might decode to @Nullable Map or to java.util.@Nullable Map or even to java.util.@javax.annotation.Nullable Map.

    • Constructor Detail

      • TypeEncoder

        private TypeEncoder()
    • Method Detail

      • encode

        static java.lang.String encode​(javax.lang.model.type.TypeMirror type)
        Returns the encoding for the given type, where class names are marked by special tokens. The encoding for int will be int, but the encoding for java.util.List<java.lang.Integer> will be `java.util.List`<`java.lang.Integer`>.
      • encodeRaw

        static java.lang.String encodeRaw​(javax.lang.model.type.TypeMirror type)
        Like encode(javax.lang.model.type.TypeMirror), except that only the raw type is encoded. So if the given type is java.util.List<java.lang.Integer> the result will be `java.util.List`.
      • encodeWithAnnotations

        static java.lang.String encodeWithAnnotations​(javax.lang.model.type.TypeMirror type)
        Encodes the given type and its type annotations. The class comment for TypeEncoder covers the details of annotation encoding.
      • decode

        static java.lang.String decode​(java.lang.String text,
                                       javax.annotation.processing.ProcessingEnvironment processingEnv,
                                       java.lang.String packageName,
                                       javax.lang.model.type.TypeMirror baseType)
        Decodes the given string, respelling class names appropriately. The text is scanned for tokens like `java.util.Locale` or `«java.util.Locale` to determine which classes are referenced. An appropriate set of imports is computed based on the set of those types. If the special token `import` appears in text then it will be replaced by this set of import statements. Then all of the tokens are replaced by the class names they represent, spelled appropriately given the import statements.
        Parameters:
        text - the text to be decoded.
        packageName - the package of the generated class. Other classes in the same package do not need to be imported.
        baseType - a class or interface that the generated class inherits from. Nested classes in that type do not need to be imported, and if another class has the same name as one of those nested classes then it will need to be qualified.
      • decode

        static java.lang.String decode​(java.lang.String text,
                                       javax.lang.model.util.Elements elementUtils,
                                       javax.lang.model.util.Types typeUtils,
                                       java.lang.String pkg,
                                       javax.lang.model.type.TypeMirror baseType)
      • className

        private static java.lang.String className​(javax.lang.model.type.DeclaredType declaredType)
      • formalTypeParametersString

        static java.lang.String formalTypeParametersString​(javax.lang.model.element.TypeElement type)
        Returns the formal type parameters of the given type. If we have @AutoValue abstract class Foo<T extends SomeClass> then this method will return an encoding of <T extends SomeClass> for Foo. Likewise it will return an encoding of the angle-bracket part of:
        Foo<SomeClass>
        Foo<T extends Number>
        Foo<E extends Enum<E>>
        Foo<K, V extends Comparable<? extends K>>.

        The encoding is simply that classes in the "extends" part are marked, so the examples will actually look something like this:
        <`bar.baz.SomeClass`>
        <T extends `java.lang.Number`>
        <E extends `java.lang.Enum`<E>>
        <K, V extends `java.lang.Comparable`<? extends K>>.

      • appendTypeParameterWithBounds

        private static void appendTypeParameterWithBounds​(javax.lang.model.element.TypeParameterElement typeParameter,
                                                          java.lang.StringBuilder sb)
      • appendAnnotations

        private static void appendAnnotations​(java.util.List<? extends javax.lang.model.element.AnnotationMirror> annotationMirrors,
                                              java.lang.StringBuilder sb)