All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.avaje.jsonb.generator.ProcessingContext Maven / Gradle / Ivy

package io.avaje.jsonb.generator;

import static io.avaje.jsonb.generator.APContext.filer;
import static io.avaje.jsonb.generator.APContext.getModuleInfoReader;
import static io.avaje.jsonb.generator.APContext.getProjectModuleElement;
import static io.avaje.jsonb.generator.APContext.jdkVersion;
import static io.avaje.jsonb.generator.APContext.logError;
import static io.avaje.jsonb.generator.APContext.logWarn;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URI;
import java.nio.file.Paths;
import java.util.*;
import javax.annotation.processing.ProcessingEnvironment;
import javax.lang.model.element.Element;
import javax.lang.model.element.TypeElement;
import javax.lang.model.type.TypeMirror;
import javax.tools.FileObject;
import javax.tools.StandardLocation;

final class ProcessingContext {

  private static final ThreadLocal CTX = new ThreadLocal<>();

  private static final class Ctx {
    private final Map importedJsonMap = new HashMap<>();
    private final Map> importedSubtypeMap = new HashMap<>();
    private final Set services = new TreeSet<>();
    private final boolean injectPresent;

    Ctx(ProcessingEnvironment env) {
      this.injectPresent = env.getElementUtils().getTypeElement("io.avaje.inject.Component") != null;
    }
  }

  private ProcessingContext() {}

  static void init(ProcessingEnvironment processingEnv) {
    APContext.init(processingEnv);
    CTX.set(new Ctx(processingEnv));
  }

  static boolean useEnhancedSwitch() {
    return jdkVersion() >= 14;
  }

  static FileObject createMetaInfWriterFor(String interfaceType) throws IOException {
    return filer().createResource(StandardLocation.CLASS_OUTPUT, "", interfaceType);
  }

  static void addImportedPrism(ImportPrism prism, Element element) {
    if (!prism.subtypes().isEmpty() && prism.value().size() > 1) {
      logError(element, "subtypes cannot be used when an import annotation imports more than one class");
      return;
    }
    final var json = CTX.get().importedJsonMap;
    final var subtypes = CTX.get().importedSubtypeMap;
    prism.value().forEach(m -> {
      final var type = m.toString();
      json.put(type, prism.jsonSettings());
      subtypes.put(type, prism.subtypes());
    });
  }

  static Optional importedJson(TypeElement type) {
    return Optional.ofNullable(CTX.get().importedJsonMap.get(type.asType().toString()));
  }

  static boolean isImported(Element element) {
    var moduleName = APContext.getProjectModuleElement().getQualifiedName();
    return !APContext.elements().getModuleOf(element).getQualifiedName().contentEquals(moduleName);
  }

  static List importedSubtypes(TypeElement type) {
    return CTX.get().importedSubtypeMap.getOrDefault(type.asType().toString(), List.of());
  }

  private static boolean buildPluginAvailable() {
    try {
      return APContext.getBuildResource("avaje-plugin-exists.txt").toFile().exists();
    } catch (final Exception e) {
      return false;
    }
  }

  static void validateModule() {
    var module = getProjectModuleElement();
    if (module != null && !module.isUnnamed()) {
      var injectPresent = CTX.get().injectPresent;

      try (var reader = getModuleInfoReader()) {
        var moduleInfo = new ModuleInfoReader(module, reader);

        moduleInfo.validateServices("io.avaje.jsonb.spi.JsonbExtension", CTX.get().services);

        boolean noInjectPlugin =
          injectPresent && !moduleInfo.containsOnModulePath("io.avaje.jsonb.plugin");

        var buildPluginAvailable = buildPluginAvailable();

        final var noDirectJsonb =
          moduleInfo.requires().stream()
            .noneMatch(r -> r.getDependency().getQualifiedName().contentEquals("io.avaje.jsonb"));

        if (noInjectPlugin && (!buildPluginAvailable || noDirectJsonb)) {
          logWarn(module, "`requires io.avaje.jsonb.plugin` must be explicitly added or else avaje-inject may fail to detect and wire the default Jsonb instance");
        }

      } catch (Exception e) {
        // can't read module
      }
    }
  }

  static void addJsonSpi(String spi) {
    CTX.get().services.add(spi);
  }

  static void clear() {
    CTX.remove();
    APContext.clear();
  }

  static Set readExistingMetaInfServices() {
    var services = CTX.get().services;
    try (final var file =
           APContext.filer()
             .getResource(StandardLocation.CLASS_OUTPUT, "", Constants.META_INF_COMPONENT)
             .toUri()
             .toURL()
             .openStream();
         final var buffer = new BufferedReader(new InputStreamReader(file));) {

      String line;
      while ((line = buffer.readLine()) != null) {
        line.replaceAll("\\s", "").replace(",", "\n").lines().forEach(services::add);
      }
    } catch (Exception e) {
      // not a critical error
    }
    return services;
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy