org.gaul.modernizer_maven_plugin.Modernizer.java Source code

Java tutorial

Introduction

Here is the source code for org.gaul.modernizer_maven_plugin.Modernizer.java

Source

/*
 * Copyright 2014 Andrew Gaul <andrew@gaul.org>
 *
 * 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 org.gaul.modernizer_maven_plugin;

import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.Label;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.commons.InstructionAdapter;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

final class Modernizer {
    private final long javaVersion;
    private final Map<String, Violation> violations;
    private final Collection<String> exclusions;
    private final Collection<String> ignorePackages;

    Modernizer(String javaVersion, Map<String, Violation> violations, Collection<String> exclusions,
            Collection<String> ignorePackages) {
        long version;
        if (javaVersion.startsWith("1.")) {
            version = Long.parseLong(javaVersion.substring(2));
        } else {
            version = Long.parseLong(javaVersion);
        }
        Utils.checkArgument(version >= 0);
        this.javaVersion = version;
        this.violations = Utils.createImmutableMap(violations);
        this.exclusions = Utils.createImmutableSet(exclusions);
        this.ignorePackages = Utils.createImmutableSet(ignorePackages);
    }

    Collection<ViolationOccurrence> check(ClassReader classReader) throws IOException {
        ModernizerClassVisitor classVisitor = new ModernizerClassVisitor(javaVersion, violations, exclusions,
                ignorePackages);
        classReader.accept(classVisitor, 0);
        return classVisitor.getOccurrences();
    }

    Collection<ViolationOccurrence> check(InputStream is) throws IOException {
        return check(new ClassReader(is));
    }

    static Map<String, Violation> parseFromXml(InputStream is)
            throws IOException, ParserConfigurationException, SAXException {
        Map<String, Violation> map = new HashMap<String, Violation>();
        DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
        DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
        Document doc = dBuilder.parse(is);
        doc.getDocumentElement().normalize();

        NodeList nList = doc.getElementsByTagName("violation");
        for (int temp = 0; temp < nList.getLength(); ++temp) {
            Node nNode = nList.item(temp);
            if (nNode.getNodeType() != Node.ELEMENT_NODE) {
                continue;
            }
            Element element = (Element) nNode;
            String version = element.getElementsByTagName("version").item(0).getTextContent();
            if (!version.startsWith("1.")) {
                throw new IllegalArgumentException("Invalid version, must have the form 1.6");
            }
            Violation violation = new Violation(element.getElementsByTagName("name").item(0).getTextContent(),
                    Integer.parseInt(version.substring(2)),
                    element.getElementsByTagName("comment").item(0).getTextContent());
            map.put(violation.getName(), violation);
        }

        return map;
    }
}

final class ModernizerClassVisitor extends ClassVisitor {
    private final long javaVersion;
    private final Map<String, Violation> violations;
    private final Collection<String> exclusions;
    private final Collection<String> ignorePackages;
    private final Collection<ViolationOccurrence> occurrences = new ArrayList<ViolationOccurrence>();
    private String packageName;

    ModernizerClassVisitor(long javaVersion, Map<String, Violation> violations, Collection<String> exclusions,
            Collection<String> ignorePackages) {
        super(Opcodes.ASM5);
        Utils.checkArgument(javaVersion >= 0);
        this.javaVersion = javaVersion;
        this.violations = Utils.checkNotNull(violations);
        this.exclusions = Utils.checkNotNull(exclusions);
        this.ignorePackages = Utils.checkNotNull(ignorePackages);
    }

    @Override
    public void visit(int version, int access, String name, String signature, String superName,
            String[] interfaces) {
        if (name.contains("/")) {
            packageName = name.substring(0, name.lastIndexOf('/')).replace('/', '.');
        } else {
            packageName = "";
        }
        for (String itr : interfaces) {
            Violation violation = violations.get(itr);
            checkToken(itr, violation, name, /*lineNumber=*/ -1);
        }
    }

    @Override
    public MethodVisitor visitMethod(int access, final String methodName, final String methodDescriptor,
            final String methodSignature, String[] exceptions) {
        MethodVisitor base = super.visitMethod(access, methodName, methodDescriptor, methodSignature, exceptions);
        MethodVisitor origVisitor = new MethodVisitor(Opcodes.ASM5, base) {
        };
        InstructionAdapter adapter = new InstructionAdapter(Opcodes.ASM5, origVisitor) {
            private int lineNumber = -1;

            @Override
            public void visitFieldInsn(int opcode, String owner, String name, String desc) {
                visitFieldOrMethod(owner, name, desc);
            }

            @Override
            public void visitMethodInsn(int opcode, String owner, String name, String desc, boolean isInterface) {
                if (name.equals("<init>")) {
                    name = "\"<init>\"";
                }
                visitFieldOrMethod(owner, name, desc);
            }

            private void visitFieldOrMethod(String owner, String name, String desc) {
                String token = owner + "." + name + ":" + desc;
                Violation violation = violations.get(token);
                checkToken(token, violation, name, lineNumber);
            }

            @Override
            public void visitLineNumber(int lineNumber, Label start) {
                this.lineNumber = lineNumber;
            }
        };
        return adapter;
    }

    private void checkToken(String token, Violation violation, String name, int lineNumber) {
        if (violation != null && !exclusions.contains(token) && javaVersion >= violation.getVersion()
                && !ignorePackages.contains(packageName)) {
            for (String prefix : ignorePackages) {
                if (packageName.startsWith(prefix + ".")) {
                    return;
                }
            }
            occurrences.add(new ViolationOccurrence(name, lineNumber, violation));
        }
    }

    Collection<ViolationOccurrence> getOccurrences() {
        return occurrences;
    }
}