org.fluidity.deployment.maven.ClassReaders.java Source code

Java tutorial

Introduction

Here is the source code for org.fluidity.deployment.maven.ClassReaders.java

Source

/*
 * Copyright (c) 2006-2016 Tibor Adam Varga (tibor.adam.varga on gmail)
 *
 * 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.fluidity.deployment.maven;

import java.io.File;
import java.io.IOException;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;

import org.fluidity.foundation.ClassLoaders;
import org.fluidity.foundation.Utility;

import org.apache.maven.plugin.MojoExecutionException;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;

/**
 * Class related convenience methods.
 *
 * @author Tibor Varga
 */
public final class ClassReaders extends Utility implements Opcodes {

    private ClassReaders() {
    }

    public static final String CONSTRUCTOR_METHOD_NAME = "<init>";

    public static boolean isInterface(final ClassReader data) {
        return (data.getAccess() & ACC_INTERFACE) != 0;
    }

    public static boolean isAbstract(final ClassReader data) {
        return (data.getAccess() & ACC_ABSTRACT) != 0;
    }

    public static boolean isFinal(final ClassReader data) {
        return (data.getAccess() & ACC_FINAL) != 0;
    }

    public static ClassWriter makePublic(final String className, final ClassReader reader)
            throws MojoExecutionException {
        assert reader != null : className;
        final ClassWriter writer = new ClassWriter(0);

        final AtomicBoolean constructorFound = new AtomicBoolean(false);

        // make class and its default constructor public
        reader.accept(new ClassVisitor(ASM5, writer) {

            @Override
            public void visit(final int version, final int access, final String name, final String signature,
                    final String superName, final String[] interfaces) {
                super.visit(version, access & ~ACC_PRIVATE & ~ACC_PROTECTED | ACC_PUBLIC, name, signature,
                        superName, interfaces);
            }

            @Override
            public MethodVisitor visitMethod(final int access, final String name, final String desc,
                    final String signature, final String[] exceptions) {
                final boolean defaultConstructor = name.equals(CONSTRUCTOR_METHOD_NAME)
                        && Type.getArgumentTypes(desc).length == 0;

                if (defaultConstructor) {
                    constructorFound.set(true);
                }

                return super.visitMethod(
                        defaultConstructor ? access & ~ACC_PRIVATE & ~ACC_PROTECTED | ACC_PUBLIC : access, name,
                        desc, signature, exceptions);
            }
        }, 0);

        if (!constructorFound.get()) {
            throw new MojoExecutionException(
                    String.format("Class %s does not have a default constructor", className));
        }

        return writer;
    }

    @SuppressWarnings("unchecked")
    public static Set<String> findDirectInterfaces(final ClassReader classData, final ClassRepository repository)
            throws IOException {
        if (classData == null) {
            return Collections.EMPTY_SET;
        }

        final String[] interfaces = classData.getInterfaces();

        if (interfaces.length > 0) {
            final Set<String> names = new HashSet<>();

            for (final String type : interfaces) {
                names.add(ClassReaders.externalName(type));
            }

            return names;
        } else {
            return findDirectInterfaces(repository.reader(classData.getSuperName()), repository);
        }
    }

    public static Set<String> findInterfaces(final ClassReader classData, final ClassRepository repository)
            throws IOException {
        return findInterfaces(classData, repository, new HashSet<>());
    }

    private static Set<String> findInterfaces(final ClassReader classData, final ClassRepository repository,
            final Set<String> list) throws IOException {
        if (classData != null) {
            final Set<String> interfaces = findDirectInterfaces(classData, repository);

            list.addAll(interfaces);

            for (final String api : interfaces) {
                findInterfaces(repository.reader(api), repository, list);
            }

            findInterfaces(repository.reader(classData.getSuperName()), repository, list);
        }

        return list;
    }

    public static String externalName(final ClassReader reader) {
        return reader.getClassName().replace('/', '.');
    }

    public static String externalName(final String className) {
        return className.replace('/', '.');
    }

    public static String internalName(final String className) {
        return className.replace('.', '/');
    }

    public static String fileName(final String className) {
        return className.replace('.', File.separatorChar).concat(ClassLoaders.CLASS_SUFFIX);
    }
}