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

tool.designpatterns.verifiers.multiclassverifiers.adapterverifier.AdapterVerifier Maven / Gradle / Ivy

The newest version!
package tool.designpatterns.verifiers.multiclassverifiers.adapterverifier;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import static tool.designpatterns.Pattern.ADAPTER_ADAPTEE;
import static tool.designpatterns.Pattern.ADAPTER_ADAPTER;

import com.github.javaparser.ast.body.ClassOrInterfaceDeclaration;
import com.github.javaparser.ast.body.FieldDeclaration;
import com.github.javaparser.ast.body.MethodDeclaration;
import com.github.javaparser.ast.expr.AnnotationExpr;
import com.github.javaparser.ast.expr.MethodCallExpr;
import com.github.javaparser.ast.type.ClassOrInterfaceType;
import com.github.javaparser.ast.visitor.GenericListVisitorAdapter;

import tool.designpatterns.Pattern;
import tool.designpatterns.PatternGroup;
import tool.designpatterns.verifiers.IPatternGrouper;
import tool.feedback.Feedback;
import tool.feedback.FeedbackTrace;
import tool.feedback.FeedbackWrapper;
import tool.feedback.PatternGroupFeedback;

/**
 * A verifier for the adapter pattern.
 */
public class AdapterVerifier implements IPatternGrouper {

    public AdapterVerifier() {
    }

    /**
     * A method for verifying one or more instances of the adapter pattern in a project.
     *
     * @param patternParts The classes that are marked with a adapter annotation
     *
     * @return a Feedback with true or false regarding if the pattern is implemented successfully.
     */
    @Override
    @SuppressWarnings("PMD.AvoidInstantiatingObjectsInLoops")
    public PatternGroupFeedback verifyGroup(
        Map> patternParts) {
        List feedbacks = new ArrayList<>();

        Feedback partsFeedback = verifyParts(patternParts);
        if (partsFeedback.getIsError()) {
            feedbacks.add(partsFeedback);
        } else {
            List adaptees = patternParts.get(ADAPTER_ADAPTEE);
            List notMatchingAdaptees = new ArrayList<>(adaptees);

            for (ClassOrInterfaceDeclaration adapter : patternParts.get(ADAPTER_ADAPTER)) {
                FeedbackWrapper> foo = verifyAdapter(adapter,
                                                                                       adaptees);
                if (!foo.getFeedback().getIsError()) {
                    notMatchingAdaptees.removeAll(foo.getOther());
                }
                feedbacks.add(foo.getFeedback());
            }
            for (ClassOrInterfaceDeclaration adaptee : notMatchingAdaptees) {
                feedbacks.add(Feedback
                                  .getNoChildFeedback("Annotated adaptee has no matching adapter",
                                                      new FeedbackTrace(adaptee))); // Suppressed
                // warning
            }
        }
        return new PatternGroupFeedback(PatternGroup.ADAPTER, feedbacks);
    }

    private Feedback verifyParts(Map> patternParts) {
        StringBuilder stringBuilder = new StringBuilder(62);
        boolean allParts = true;
        if (!patternParts.containsKey(ADAPTER_ADAPTER) || patternParts.get(ADAPTER_ADAPTER)
                                                                      .isEmpty()) {
            allParts = false;
            stringBuilder.append("There is no annotated adapter, ");
        }

        if (!patternParts.containsKey(ADAPTER_ADAPTEE) || patternParts.get(ADAPTER_ADAPTEE)
                                                                      .isEmpty()) {
            allParts = false;
            stringBuilder.append("There is no annotated adaptee, ");
        }

        if (allParts) {
            return Feedback.getSuccessfulFeedback();
        } else {
            return Feedback.getPatternInstanceNoChildFeedback(
                stringBuilder.delete(stringBuilder.length() - 2, stringBuilder.length())
                             .toString());
        }
    }

    /**
     * A method to verify the implementation of a single adapter pattern.
     *
     * @param adapter  The adapter classOrInterfaceDeclaration for the specific pattern instance
     * @param adaptees A list of all possible classOrInterfaceDeclaration adaptees
     *
     * @return A feedbackWrapper with the result of the verification and a list of adaptees for the
     *     adapter
     */
    private FeedbackWrapper> verifyAdapter(
        ClassOrInterfaceDeclaration adapter, List adaptees) {
        MethodDeclarationVisitor methodVisitor = new MethodDeclarationVisitor(adapter);

        List feedbacks = new ArrayList<>();
        List candidateAdaptees = new ArrayList<>(); // Since an
        // adapter can be used for multiple adaptees we need to save each candidate
        for (ClassOrInterfaceDeclaration adaptee : adaptees) {
            for (Boolean methodWraps : adapter.accept(methodVisitor, adaptee)) {
                if (methodWraps) {
                    feedbacks.add(verifyInterfaces(adapter, adaptee));
                    candidateAdaptees.add(adaptee);
                    //return new FeedbackWrapper<>(verifyInterfaces(adapter, adaptee), adaptee);
                }
            }

        }
        if (feedbacks.isEmpty()) {
            return new FeedbackWrapper<>(Feedback.getNoChildFeedback(
                "Adapter does not wrap the adaptee", new FeedbackTrace(adapter)), null);
        } else {
            return new FeedbackWrapper<>(
                Feedback.getFeedbackWithChildren(new FeedbackTrace(adapter), feedbacks),
                candidateAdaptees);
        }
    }

    /**
     * A method for verifying that the adaptor does not implement the interface of the adaptee or
     * extend the adaptee.
     *
     * @param adapter The ClassOrInterfaceDeclaration for the adapter
     * @param adaptee The ClassOrInterfaceDeclaration of the interface or superclass to be adapted
     *
     * @return Boolean regarding if the implementation is correct or not.
     */
    @SuppressWarnings("PMD.AvoidInstantiatingObjectsInLoops") // The only instantiated objects in
    // loops are in return statements
    private Feedback verifyInterfaces(
        ClassOrInterfaceDeclaration adapter, ClassOrInterfaceDeclaration adaptee) {
        for (ClassOrInterfaceType coit : adapter.getImplementedTypes()) {
            if (adaptee.isInterface()) {
                if (coit.getNameAsString().equalsIgnoreCase(adaptee.getNameAsString())) {
                    return Feedback.getNoChildFeedback("The adapter implements the adaptee",
                                                       new FeedbackTrace(adapter));
                }
            } else {
                for (ClassOrInterfaceType coi : adaptee.getImplementedTypes()) {
                    if (coit.getNameAsString().equalsIgnoreCase(coi.getNameAsString())) {
                        return Feedback.getNoChildFeedback(
                            "The adapter implements the same interface as the adaptee",
                            new FeedbackTrace(adapter));
                    }
                }
            }
        }

        return Feedback.getSuccessfulFeedback();
    }

    /**
     * A class used to visit nodes in a AST created by JavaParser.
     */

    private static class MethodDeclarationVisitor
        extends GenericListVisitorAdapter {

        private final ClassOrInterfaceDeclaration currentClass;

        public MethodDeclarationVisitor(ClassOrInterfaceDeclaration currentClass) {
            super();
            this.currentClass = currentClass;
        }

        /**
         * A method for visiting MethodDeclarations in ClassOrInterfaceDeclarations. Visits the
         * MethodDeclarations and checks if they are overridden. If they are a true feedback is
         * added to the list, otherwise a false is added.
         *
         * @param method  The MethodDeclaration of the method to be checked.
         * @param adaptee The ClassOrInterfaceDeclaration of the adaptees method to be wrapped.
         *
         * @return a list of booleans
         */
        @Override
        public List visit(
            MethodDeclaration method, ClassOrInterfaceDeclaration adaptee) {
            List resultList = super.visit(method, adaptee);
            for (AnnotationExpr annotation : method.getAnnotations()) {
                if (annotation.getNameAsString().equalsIgnoreCase("override")) {
                    resultList.add(isWrapper(method, currentClass, adaptee));
                    return resultList;
                }
            }
            resultList.add(Boolean.FALSE);
            return resultList;
        }

        /**
         * A method that checks if a method is called from within another method, i.e. if it is
         * wrapped.
         *
         * @param method  The MethodDeclaration fo the wrapping method.
         * @param adaptee The ClassOrInterfaceDeclaration to look for the wrapped method in.
         *
         * @return a boolean, true if it is wrapped, otherwise false.
         */
        private Boolean isWrapper(
            MethodDeclaration method, ClassOrInterfaceDeclaration currentClass,
            ClassOrInterfaceDeclaration adaptee) {
            List list = method.accept(new MethodCallVisitor(currentClass), adaptee);

            return list.stream().anyMatch(e -> e);
        }
    }


    /**
     * A class used to visit every method call expression node in a ClassOrInterfaceDeclaration.
     */
    private static class MethodCallVisitor
        extends GenericListVisitorAdapter {

        private final ClassOrInterfaceDeclaration currentClass;

        public MethodCallVisitor(ClassOrInterfaceDeclaration currentClass) {
            super();
            this.currentClass = currentClass;
        }

        /**
         * Checks if the adaptee is an interface or a superclass, and checks whether the method call
         * wraps a method call from the adaptee, if it does it adds true to the list otherwise it
         * returns false.
         *
         * @param methodCallExpr the type of node to be visited
         * @param adaptee        the ClassOrInterfaceDeclaration nodes are being visited in.
         *
         * @return a list of Booleans, true if wrapped method call otherwise false.
         */
        @Override
        public List visit(
            MethodCallExpr methodCallExpr, ClassOrInterfaceDeclaration adaptee) {
            List boolList = super.visit(methodCallExpr, adaptee);

            if (adaptee.isInterface()) {
                for (FieldDeclaration field : currentClass.getFields()) {
                    if (field.getCommonType().toString().equals(adaptee.getNameAsString())) {
                        boolList.add(Boolean.TRUE);
                        return boolList;
                    }
                }
            } else if (methodCallExpr.getScope().get().toString().equalsIgnoreCase("super")) {
                boolList.add(Boolean.TRUE);
                return boolList;
            }

            boolList.add(Boolean.FALSE);
            return boolList;
        }
    }

}







© 2015 - 2025 Weber Informatics LLC | Privacy Policy