L
L
LookAtIos2018-07-12 20:10:59
Java
LookAtIos, 2018-07-12 20:10:59

How to run 10000 classes in java?

An interesting task for java: run 1000 classes in the project that display the class number. Just copying and compiling is probably not right. What are the best ways to solve the problem?

Answer the question

In order to leave comments, you need to log in

2 answer(s)
S
Sergey Gornostaev, 2018-07-13
@LookAtIos

First of all, it should be noted that you cannot run a class, you can only declare it, and you can run methods of instances of this class. That's why I thought the question was worded wrong.
But if the question is about declaring new classes at runtime, then this is called code generation. And, firstly, reflection is powerless in this, and secondly, this is a very complex topic, which only a very vile troll could puzzle a novice programmer.
You can generate both java code and bytecode. The first method is used by the popular Lombok library . It will need a mechanism for working with ASTand a mechanism for interacting with the compiler. Oracle JDK and Open JDK provide a Compiler API that implements both mechanisms. In addition, there are other tools for working with ASTs, such as Eclipse JDT. I'll show you how to use the com.sun.tools.javac package from the Compiler API.

Footnote
До Java 9 пакет com.sun.tools.javac был упакован в tools.jar, поставляемый вместе с JDK. Начиная с 9-ки API компилятора вынесли в модуль jdk.compiler, не экспортирующие свои пакеты. Теперь можно не указывать путь до tools.jar в classpath, но нужно добавлять экспорты. В остальном ничего не изменилось.
import java.lang.reflect.Method;
import java.net.URI;
import java.util.ArrayList;
 
import javax.tools.JavaCompiler;
import javax.tools.JavaCompiler.CompilationTask;
import javax.tools.JavaFileObject;
import javax.tools.SimpleJavaFileObject;
import javax.tools.ToolProvider;

import com.sun.tools.javac.code.Flags;
import com.sun.tools.javac.code.Type;
import com.sun.tools.javac.file.JavacFileManager;
import com.sun.tools.javac.model.JavacElements;
import com.sun.tools.javac.processing.JavacProcessingEnvironment;
import com.sun.tools.javac.tree.JCTree;
import com.sun.tools.javac.tree.TreeMaker;
import com.sun.tools.javac.util.Context;
import com.sun.tools.javac.util.List;
import com.sun.tools.javac.util.Name;


/**
 * Класс эмулирующий для компилятора файлы исходного кода
 * и позволяющий компилировать код прямо из памяти
 */
class JavaSourceFromString extends SimpleJavaFileObject {
    private final String code;

    public JavaSourceFromString(String name, String code) {
        super(URI.create("string:///" + name.replace('.','/') + Kind.SOURCE.extension), Kind.SOURCE);
        this.code = code;
    }

    @Override
    public CharSequence getCharContent(boolean ignoreEncodingErrors) {
        return code;
    }
}
 
public class CompilerDemo {
    private static final String BASE_NAME = "DynamicHello";
    private static final ClassLoader classLoader = ToolProvider.getSystemToolClassLoader();
    private static final JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();

    /**
     * Метод формирующий абстрактное синтаксическое дерево
     * и преобразующий его в исходный код
     */
    private static String generateSource(String className) {
        Context ctx = new Context();
        JavacFileManager.preRegister(ctx);
        TreeMaker treeMaker = TreeMaker.instance(ctx);
        JavacElements elements = JavacElements.instance(ctx);

        JCTree.JCModifiers modifiers = treeMaker.Modifiers(Flags.PUBLIC);

        // Тело генерируемого метода
        // выводящее имя класса
        JCTree.JCBlock methodBody = treeMaker.Block(0, List.of(
            treeMaker.Exec(
                treeMaker.Apply(
                    List.<JCTree.JCExpression>nil(),
                    treeMaker.Select(
                        treeMaker.Select(
                            treeMaker.Ident(
                                elements.getName("System")
                            ),
                            elements.getName("out")
                        ),
                        elements.getName("println")
                    ),
                    List.<JCTree.JCExpression>of(
                        treeMaker.Binary(
                            JCTree.Tag.PLUS,
                            treeMaker.Literal("I am "),
                            treeMaker.Apply(
                                List.<JCTree.JCExpression>nil(),
                                treeMaker.Select(
                                    treeMaker.Apply(
                                        List.<JCTree.JCExpression>nil(),
                                        treeMaker.Select(
                                            treeMaker.Ident(
                                                elements.getName("this")
                                            ),
                                            elements.getName("getClass")
                                        ),
                                        List.<JCTree.JCExpression>nil()
                                    ),
                                    elements.getName("getName")
                                ),
                                List.<JCTree.JCExpression>nil()
                            )
                        )
                    )
                )
            )
        ));

        // Определение генерируемого метода
        JCTree.JCMethodDecl method = treeMaker.MethodDef(
            modifiers,
            elements.getName("introduceYourself"),
            treeMaker.Type(new Type.JCVoidType()),
            List.<JCTree.JCTypeParameter>nil(),
            List.<JCTree.JCVariableDecl>nil(),
            List.<JCTree.JCExpression>nil(),
            methodBody,
            null
        );

        // Определение генерируемого класса
        JCTree.JCClassDecl tree = treeMaker.ClassDef(
            modifiers,
            elements.getName(className),
            List.<JCTree.JCTypeParameter>nil(),
            null,
            List.<JCTree.JCExpression>nil(),
            List.of(method)
        );

        return tree.toString();
    }

    /**
     * Метод компилирующий исходный код
     */
    public static void compile(Iterable<? extends JavaFileObject> compilationUnits) {
        CompilationTask task = compiler.getTask(null, null, null, null, null, compilationUnits);
        task.call();    
    }


    /**
     * Метод запускающий сгенерированные классы с помощью рефлексии
     */    
    public static void loadAndRun(String className) throws ReflectiveOperationException {
        Class<?> cls = classLoader.loadClass(className);
        
        Method method = cls.getDeclaredMethod("introduceYourself");
        method.invoke(cls.newInstance());    
    }

    public static void main(String[] args) throws Exception {
        java.util.List<JavaFileObject> sources = new ArrayList<>();

        // Генерируем исходный код десятка классов
        for (int x = 0; x < 10; x++) {
            String className = BASE_NAME + x;
            sources.add(new JavaSourceFromString(className, generateSource(className)));
        }

        // Компилируем сгенерированный код
        compile(sources);
        
        // Запускаем скомпилированные классы
        for (int x = 0; x < 10; x++) {
            loadAndRun(BASE_NAME + x);
        }
    }
}

Of course, you could not bother with AST, just put the code in a string literal, substitute different names in this literal and slip it to the compiler. But it's not that interesting!
Continued in the first comment , otherwise I do not fit into the character limit.

I
illuzor, 2018-07-12
@iLLuzor

The simplest is cycles.
More complicated - cycles and flows.

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question