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

br.com.objectos.code.CodeResources Maven / Gradle / Ivy

The newest version!
/*
 * Copyright 2016 Objectos, Fábrica de Software LTDA.
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */
package br.com.objectos.code;

import java.lang.annotation.Annotation;
import java.lang.reflect.TypeVariable;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;

import javax.tools.JavaFileObject;

import br.com.objectos.core.util.ArrayListMultimap;
import br.com.objectos.core.util.ImmutableList;
import br.com.objectos.core.util.ImmutableMap;
import br.com.objectos.core.util.Multimap;

import com.google.common.truth.Truth;
import com.google.testing.compile.JavaFileObjects;
import com.google.testing.compile.JavaSourcesSubjectFactory;

/**
 * @author [email protected] (Marcio Endo)
 */
public class CodeResources {

  private final List methodInfoList;
  private final List packageInfoList;
  private final Map typeInfoMap;

  private CodeResources(List methodInfoList,
                        List packageInfoList,
                        Map typeInfoMap) {
    this.methodInfoList = methodInfoList;
    this.packageInfoList = packageInfoList;
    this.typeInfoMap = typeInfoMap;
  }

  public static CodeResourcesBuilder builder() {
    return new Builder();
  }

  public List methodInfoList() {
    return methodInfoList;
  }

  public PackageInfo packageInfo(String qualifiedName) {
    return packageInfoList.stream()
        .filter(pkg -> pkg.name().equals(qualifiedName))
        .findFirst()
        .orElseThrow(() -> new NoSuchElementException(qualifiedName));
  }

  public List packageInfoList() {
    return packageInfoList;
  }

  public TypeInfo typeInfo(String qualifiedName) {
    TypeInfo typeInfo = typeInfoMap.get(qualifiedName);
    if (typeInfo == null) {
      throw new NoSuchElementException(qualifiedName);
    }
    return typeInfo;
  }

  @FunctionalInterface
  public static interface MethodInfoListener {
    void onMethodInfo(MethodInfo methodInfo);
  }

  @FunctionalInterface
  public static interface PackageInfoListener {
    void onPackageInfo(PackageInfo packageInfo);
  }

  @FunctionalInterface
  public static interface TypeInfoListener {
    void onTypeInfo(TypeInfo typeInfo);
  }

  private static class Builder
      extends AbstractAnnotationProcessor
      implements
      CodeResourcesBuilder,
      CodeResourcesBuilder.AddAnnotationType,
      CodeResourcesBuilder.AddListener,
      CodeResourcesBuilder.AddResource,
      CodeResourcesBuilder.AddIsSubtype {

    private final Set annotationTypeSet = new HashSet<>();
    private final Set methodInfoListenerSet = new LinkedHashSet<>(2);
    private final Set packageInfoListenerSet = new LinkedHashSet<>(2);
    private final Set typeInfoListenerSet = new LinkedHashSet<>(2);
    private final List resourceNameList = new ArrayList<>();

    private final ImmutableList.Builder methodInfoList = ImmutableList.builder();
    private final ImmutableList.Builder packageInfoList = ImmutableList.builder();
    private final Multimap, String> subtypeMap = ArrayListMultimap.create();
    private final ImmutableMap.Builder typeInfoMap = ImmutableMap.builder();

    @Override
    public AddAnnotationType addAnnotationType(Class annotationType) {
      Objects.requireNonNull(annotationType);
      annotationTypeSet.add(annotationType.getName());
      return this;
    }

    @Override
    public AddIsSubtype addSubType(Class superType, Class subType) {
      TypeVariable[] typeParameters = subType.getTypeParameters();
      int length = typeParameters.length;
      switch (length) {
      case 0:
        return addSubType(superType, subType.getCanonicalName());
      case 1:
        return addSubType(superType, subType.getCanonicalName() + "");
      default:
        StringBuilder rawName = new StringBuilder(subType.getCanonicalName());
        rawName.append("');
        return addSubType(superType, rawName.toString());
      }
    }

    @Override
    public AddIsSubtype addSubType(Class superType, String subTypeName) {
      Objects.requireNonNull(superType);
      Objects.requireNonNull(subTypeName);
      subtypeMap.put(superType, subTypeName);
      return this;
    }

    @Override
    public AddListener addMethodInfoListener(MethodInfoListener listener) {
      Objects.requireNonNull(listener);
      methodInfoListenerSet.add(listener);
      return this;
    }

    @Override
    public AddListener addPackageInfoListener(PackageInfoListener listener) {
      Objects.requireNonNull(listener);
      packageInfoListenerSet.add(listener);
      return this;
    }

    @Override
    public AddListener addTypeInfoListener(TypeInfoListener listener) {
      Objects.requireNonNull(listener);
      typeInfoListenerSet.add(listener);
      return this;
    }

    @Override
    public AddResource addResource(String resourceName) {
      Objects.requireNonNull(resourceName);
      String name = resourceName.startsWith("/")
          ? resourceName.substring(1)
          : resourceName;
      resourceNameList.add(name);
      return this;
    }

    @Override
    public CodeResources build() {
      List objectList = resourceNameList.stream()
          .map(name -> JavaFileObjects.forResource(name))
          .collect(Collectors.toList());

      Truth.assertAbout(JavaSourcesSubjectFactory.javaSources())
          .that(objectList)
          .processedWith(this)
          .compilesWithoutError();

      return new CodeResources(
          methodInfoList.build(),
          packageInfoList.build(),
          typeInfoMap.build());
    }

    @Override
    protected Configuration configuration() {
      return Configuration.builder()
          .addAllAnnotationTypesByName(annotationTypeSet)
          .addMethodInfoArtifactGenerator(this::methodInfo)
          .addPackageInfoArtifactGenerator(this::packageInfo)
          .addTypeInfoArtifactGenerator(this::typeInfo)
          .listener(new TestingProcessorListener(subtypeMap))
          .build();
    }

    private Artifact methodInfo(TypeInfo typeInfo, MethodInfo methodInfo) {
      methodInfoList.add(methodInfo);
      methodInfoListenerSet.forEach(listener -> listener.onMethodInfo(methodInfo));
      return Artifact.empty();
    }

    private Artifact packageInfo(PackageInfo packageInfo) {
      packageInfoList.add(ForwardingPackageInfo.of(packageInfo));
      packageInfoListenerSet.forEach(listener -> listener.onPackageInfo(packageInfo));
      return Artifact.empty();
    }

    private Artifact typeInfo(TypeInfo typeInfo) {
      typeInfoMap.put(typeInfo.qualifiedName(), typeInfo);
      typeInfoListenerSet.forEach(listener -> listener.onTypeInfo(typeInfo));
      return Artifact.empty();
    }

  }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy