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

com.tngtech.archunit.core.domain.JavaClassMembers Maven / Gradle / Ivy

Go to download

A Java architecture test library, to specify and assert architecture rules in plain Java - Module 'archunit'

The newest version!
/*
 * Copyright 2014-2024 TNG Technology Consulting GmbH
 *
 * 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 com.tngtech.archunit.core.domain;

import java.util.Comparator;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.SortedSet;
import java.util.TreeSet;
import java.util.function.Supplier;

import com.google.common.collect.ComparisonChain;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.tngtech.archunit.base.Suppliers;

import static com.google.common.collect.Iterables.concat;
import static com.google.common.collect.Iterables.getOnlyElement;
import static com.tngtech.archunit.base.Optionals.asSet;
import static com.tngtech.archunit.core.domain.JavaConstructor.CONSTRUCTOR_NAME;
import static com.tngtech.archunit.core.domain.JavaModifier.ENUM;
import static com.tngtech.archunit.core.domain.JavaModifier.SYNTHETIC;
import static com.tngtech.archunit.core.domain.properties.HasName.Utils.namesOf;
import static java.util.Collections.emptySet;
import static java.util.stream.Collectors.toSet;

class JavaClassMembers {
    private final JavaClass owner;
    private final Set fields;
    private final Set codeUnits;
    private final Set methods;
    private final Set members;
    private final Set constructors;
    private final Optional staticInitializer;
    private final Supplier> allMethods;
    private final Supplier> allConstructors;
    private final Supplier> allFields;
    private final Supplier> allMembers = Suppliers.memoize(() -> ImmutableSet.builder()
            .addAll(getAllFields())
            .addAll(getAllMethods())
            .addAll(getAllConstructors())
            .build());

    JavaClassMembers(JavaClass owner, Set fields, Set methods, Set constructors, Optional staticInitializer) {
        this.owner = owner;
        this.fields = fields;
        this.methods = methods;
        this.constructors = constructors;
        this.staticInitializer = staticInitializer;
        this.codeUnits = ImmutableSet.builder()
                .addAll(methods).addAll(constructors).addAll(asSet(staticInitializer))
                .build();
        this.members = ImmutableSet.builder()
                .addAll(fields)
                .addAll(methods)
                .addAll(constructors)
                .build();
        allFields = Suppliers.memoize(() -> {
            ImmutableSet.Builder result = ImmutableSet.builder();
            for (JavaClass javaClass : concat(owner.getClassHierarchy(), owner.getAllRawInterfaces())) {
                result.addAll(javaClass.getFields());
            }
            return result.build();
        });
        allMethods = Suppliers.memoize(() -> {
            ImmutableSet.Builder result = ImmutableSet.builder();
            for (JavaClass javaClass : concat(owner.getClassHierarchy(), owner.getAllRawInterfaces())) {
                result.addAll(javaClass.getMethods());
            }
            return result.build();
        });
        allConstructors = Suppliers.memoize(() -> {
            ImmutableSet.Builder result = ImmutableSet.builder();
            for (JavaClass javaClass : owner.getClassHierarchy()) {
                result.addAll(javaClass.getConstructors());
            }
            return result.build();
        });
    }

    Set get() {
        return members;
    }

    Set getAll() {
        return allMembers.get();
    }

    Set getFields() {
        return fields;
    }

    Set getAllFields() {
        return allFields.get();
    }

    public JavaField getField(String name) {
        Optional field = tryGetField(name);
        if (!field.isPresent()) {
            throw new IllegalArgumentException("No field with name '" + name + " in class " + owner.getName());
        }
        return field.get();
    }

    Optional tryGetField(String name) {
        for (JavaField field : fields) {
            if (name.equals(field.getName())) {
                return Optional.of(field);
            }
        }
        return Optional.empty();
    }

    Set getCodeUnits() {
        return codeUnits;
    }

    JavaCodeUnit getCodeUnitWithParameterTypeNames(String name, List parameters) {
        return findMatchingCodeUnit(codeUnits, name, parameters);
    }

    Optional tryGetCodeUnitWithParameterTypeNames(String name, List parameters) {
        return tryFindMatchingCodeUnit(codeUnits, name, parameters);
    }

    JavaMethod getMethod(String name, List parameterTypeNames) {
        return findMatchingCodeUnit(methods, name, ImmutableList.copyOf(parameterTypeNames));
    }

    Optional tryGetMethod(String name, List parameterTypeNames) {
        return tryFindMatchingCodeUnit(methods, name, parameterTypeNames);
    }

    Set getMethods() {
        return methods;
    }

    Set getAllMethods() {
        return allMethods.get();
    }

    JavaConstructor getConstructor(List parameterTypeNames) {
        return findMatchingCodeUnit(constructors, CONSTRUCTOR_NAME, parameterTypeNames);
    }

    Optional tryGetConstructor(List parameterTypeNames) {
        return tryFindMatchingCodeUnit(constructors, CONSTRUCTOR_NAME, parameterTypeNames);
    }

    Set getConstructors() {
        return constructors;
    }

    Set getAllConstructors() {
        return allConstructors.get();
    }

    Optional getStaticInitializer() {
        return staticInitializer;
    }

    Set getEnumConstants() {
        ImmutableSet.Builder result = ImmutableSet.builder();
        for (JavaField field : fields) {
            if (field.getModifiers().contains(ENUM)) {
                result.add(new JavaEnumConstant(owner, field.getName()));
            }
        }
        return result.build();
    }

    Set getInstanceofChecks() {
        ImmutableSet.Builder result = ImmutableSet.builder();
        for (JavaCodeUnit codeUnit : codeUnits) {
            result.addAll(codeUnit.getInstanceofChecks());
        }
        return result.build();
    }

    Set getReferencedClassObjects() {
        ImmutableSet.Builder result = ImmutableSet.builder();
        for (JavaCodeUnit codeUnit : codeUnits) {
            result.addAll(codeUnit.getReferencedClassObjects());
        }
        return result.build();
    }

    Set getFieldAccessesFromSelf() {
        ImmutableSet.Builder result = ImmutableSet.builder();
        for (JavaCodeUnit codeUnit : codeUnits) {
            result.addAll(codeUnit.getFieldAccesses());
        }
        return result.build();
    }

    Set getMethodCallsFromSelf() {
        ImmutableSet.Builder result = ImmutableSet.builder();
        for (JavaCodeUnit codeUnit : codeUnits) {
            result.addAll(codeUnit.getMethodCallsFromSelf());
        }
        return result.build();
    }

    Set getConstructorCallsFromSelf() {
        ImmutableSet.Builder result = ImmutableSet.builder();
        for (JavaCodeUnit codeUnit : codeUnits) {
            result.addAll(codeUnit.getConstructorCallsFromSelf());
        }
        return result.build();
    }

    Set getMethodReferencesFromSelf() {
        ImmutableSet.Builder result = ImmutableSet.builder();
        for (JavaCodeUnit codeUnit : codeUnits) {
            result.addAll(codeUnit.getMethodReferencesFromSelf());
        }
        return result.build();
    }

    Set getConstructorReferencesFromSelf() {
        ImmutableSet.Builder result = ImmutableSet.builder();
        for (JavaCodeUnit codeUnit : codeUnits) {
            result.addAll(codeUnit.getConstructorReferencesFromSelf());
        }
        return result.build();
    }

    Set getFieldAccessesToSelf() {
        ImmutableSet.Builder result = ImmutableSet.builder();
        for (JavaField field : fields) {
            result.addAll(field.getAccessesToSelf());
        }
        return result.build();
    }

    Set getMethodCallsToSelf() {
        ImmutableSet.Builder result = ImmutableSet.builder();
        for (JavaMethod method : methods) {
            result.addAll(method.getCallsOfSelf());
        }
        return result.build();
    }

    Set getMethodReferencesToSelf() {
        ImmutableSet.Builder result = ImmutableSet.builder();
        for (JavaMethod method : methods) {
            result.addAll(method.getReferencesToSelf());
        }
        return result.build();
    }

    Set getConstructorCallsToSelf() {
        ImmutableSet.Builder result = ImmutableSet.builder();
        for (JavaConstructor constructor : constructors) {
            result.addAll(constructor.getCallsOfSelf());
        }
        return result.build();
    }

    Set getConstructorReferencesToSelf() {
        ImmutableSet.Builder result = ImmutableSet.builder();
        for (JavaConstructor constructor : constructors) {
            result.addAll(constructor.getReferencesToSelf());
        }
        return result.build();
    }

    private  T findMatchingCodeUnit(Set codeUnits, String name, List parameters) {
        Optional codeUnit = tryFindMatchingCodeUnit(codeUnits, name, parameters);
        if (!codeUnit.isPresent()) {
            throw new IllegalArgumentException(
                    String.format("No code unit with name '%s' and parameters %s in codeUnits %s of class %s",
                            name, parameters, codeUnits, owner.getName()));
        }
        return codeUnit.get();
    }

    private  Optional tryFindMatchingCodeUnit(Set codeUnits, String name, List parameters) {
        Set matching = findCodeUnitsWithMatchingNameAndParameters(codeUnits, name, parameters);

        if (matching.isEmpty()) {
            return Optional.empty();
        } else if (matching.size() == 1) {
            return Optional.of(getOnlyElement(matching));
        } else {
            // In this case we have some synthetic methods like bridge methods making name and parameters alone ambiguous
            // We want to return the non-synthetic method first because that is usually the relevant one for users
            SortedSet sortedByPriority = new TreeSet<>(SORTED_BY_SYNTHETIC_LAST_THEN_FULL_NAME);
            sortedByPriority.addAll(matching);
            return Optional.of(sortedByPriority.first());
        }
    }

    private  Set findCodeUnitsWithMatchingNameAndParameters(Set codeUnits, String name, List parameters) {
        return codeUnits.stream()
                .filter(codeUnit -> name.equals(codeUnit.getName()))
                .filter(codeUnit -> parameters.equals(namesOf(codeUnit.getRawParameterTypes())))
                .collect(toSet());
    }

    void completeAnnotations(ImportContext context) {
        for (JavaMember member : members) {
            member.completeAnnotations(context);
        }
    }

    void completeFrom(ImportContext context) {
        for (JavaCodeUnit codeUnit : codeUnits) {
            codeUnit.completeFrom(context);
        }
    }

    void setReverseDependencies(ReverseDependencies reverseDependencies) {
        for (JavaMember member : members) {
            member.setReverseDependencies(reverseDependencies);
        }
    }

    private static final Comparator SORTED_BY_SYNTHETIC_LAST_THEN_FULL_NAME =
            (codeUnit1, codeUnit2) -> ComparisonChain.start()
                    .compareTrueFirst(!codeUnit1.getModifiers().contains(SYNTHETIC), !codeUnit2.getModifiers().contains(SYNTHETIC))
                    .compare(codeUnit1.getFullName(), codeUnit2.getFullName())
                    .result();

    static JavaClassMembers empty(JavaClass owner) {
        return new JavaClassMembers(
                owner,
                emptySet(),
                emptySet(),
                emptySet(),
                Optional.empty());
    }

    static JavaClassMembers create(JavaClass owner, ImportContext context) {
        return new JavaClassMembers(
                owner,
                context.createFields(owner),
                context.createMethods(owner),
                context.createConstructors(owner),
                context.createStaticInitializer(owner));
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy