[Java] Vereinigen Sie diese NG, wenn eine Methode mit einer großen Anzahl von Zeilen mithilfe von schwarzer Magie erkannt wird

Annahmen: Java11, JUnit5, sbt

Ich habe die Monstermethode satt, also habe ich so etwas geschrieben ... Bereiten wir es zu Beginn des Projekts vor.

Als Ergebnis der Vorbereitung so etwas Ich habe die Methoden aufgeteilt und vorerst die Anzahl der Zeilen pro Methode reduziert, Stattdessen könnte es zu einer globalen Variablen gemacht werden, indem der Bereich der Variablen erweitert wird, sodass mit verschiedenen Methoden auf sie verwiesen werden kann. Es gibt ein Problem, dass ... Vielleicht ist es dieses Mal noch besser, dieses vorzubereiten? Ich denke.

Fügen Sie ↓ in libraryDependencies von build.sbt ein

build.sbt


  "org.junit.jupiter" % "junit-jupiter-api" % "5.5.0",
  "org.junit.jupiter"%"junit-jupiter-engine" % "5.5.0",
  "org.javassist" % "javassist" % "3.25.0-GA",

Code

package com.github.momosetkn;

import javassist.ClassPool;
import org.junit.jupiter.api.Test;

import java.io.File;
import java.io.IOException;
import java.net.URISyntaxException;
import java.nio.file.*;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.ArrayList;
import java.util.List;

class MonsterMethodAlert {

    @Test
    void test() throws Exception {
        var cp = ClassPool.getDefault();
        var fail = false;
        for (var className : getClassNameList()) {
            var cc = cp.get(className);
            for (var method : cc.getMethods()) {
                // java.lang.Object.Methoden unter Java-Paket wie gleich sind ausgeschlossen
                if (method.getDeclaringClass().getName().startsWith("java"))
                    continue;
                var methodInfo = method.getMethodInfo();
                var start = methodInfo.getLineNumber(Integer.MIN_VALUE);
                var end = methodInfo.getLineNumber(Integer.MAX_VALUE);
                var line = end - start + 1;
                if (line >= 25) {
                    System.err.println(String.format("%s%Es ist eine Monstermethode der Linie", className + "#" + methodInfo.getName(), line));
                    fail = true;
                }
            }
        }
        if (fail)
            throw new Exception("Monstermethode erkannt");
    }

    private List<String> getClassNameList() throws IOException, URISyntaxException {
        var list = new ArrayList<String>();
        var classLoader = Thread.currentThread().getContextClassLoader();
        var targetUrls = classLoader.getResources("");
        var CLASS_EXT = ".class";
        while (targetUrls.hasMoreElements()) {
            var url = targetUrls.nextElement();
            if (!url.getProtocol().equals("file")) {
                continue;
            }
            var targetPath = Paths.get(url.toURI());
            Files.walkFileTree(targetPath, new SimpleFileVisitor<>() {
                @Override
                public FileVisitResult visitFile(Path foundPath, BasicFileAttributes attrs) throws IOException {
                    if (foundPath.toString().endsWith(CLASS_EXT)){
                        var relativizeStr = targetPath.relativize(foundPath).toString();
                        list.add(
                                relativizeStr
                                            .substring(0, relativizeStr.length() - CLASS_EXT.length())
                                            .replace(File.separatorChar, '.')
                        );
                    }
                    return super.visitFile(foundPath, attrs);
                }
            });
        }
        return list;
    }
}
Example#main ist eine 36-zeilige Monstermethode

java.lang.Exception:Monstermethode erkannt

	at com.github.momosetkn.MonsterMethodAlert.test(MonsterMethodAlert.java:37)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.base/java.lang.reflect.Method.invoke(Method.java:566)
	at org.junit.platform.commons.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:436)
	at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:115)
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$invokeTestMethod$6(TestMethodTestDescriptor.java:170)
	at org.junit.jupiter.engine.execution.ThrowableCollector.execute(ThrowableCollector.java:40)
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeTestMethod(TestMethodTestDescriptor.java:166)
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:113)
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:58)
	at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor$NodeExecutor.lambda$executeRecursively$3(HierarchicalTestExecutor.java:112)
	at org.junit.platform.engine.support.hierarchical.SingleTestExecutor.executeSafely(SingleTestExecutor.java:66)
	at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor$NodeExecutor.executeRecursively(HierarchicalTestExecutor.java:108)
	at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor$NodeExecutor.execute(HierarchicalTestExecutor.java:79)
	at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor$NodeExecutor.lambda$executeRecursively$2(HierarchicalTestExecutor.java:120)
	at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.accept(ForEachOps.java:183)
	at java.base/java.util.stream.ReferencePipeline$2$1.accept(ReferencePipeline.java:177)
	at java.base/java.util.Iterator.forEachRemaining(Iterator.java:133)
	at java.base/java.util.Spliterators$IteratorSpliterator.forEachRemaining(Spliterators.java:1801)
	at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:484)
	at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:474)
	at java.base/java.util.stream.ForEachOps$ForEachOp.evaluateSequential(ForEachOps.java:150)
	at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateSequential(ForEachOps.java:173)
	at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
	at java.base/java.util.stream.ReferencePipeline.forEach(ReferencePipeline.java:497)
	at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor$NodeExecutor.lambda$executeRecursively$3(HierarchicalTestExecutor.java:120)
	at org.junit.platform.engine.support.hierarchical.SingleTestExecutor.executeSafely(SingleTestExecutor.java:66)
	at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor$NodeExecutor.executeRecursively(HierarchicalTestExecutor.java:108)
	at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor$NodeExecutor.execute(HierarchicalTestExecutor.java:79)
	at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor$NodeExecutor.lambda$executeRecursively$2(HierarchicalTestExecutor.java:120)
	at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.accept(ForEachOps.java:183)
	at java.base/java.util.stream.ReferencePipeline$2$1.accept(ReferencePipeline.java:177)
	at java.base/java.util.Iterator.forEachRemaining(Iterator.java:133)
	at java.base/java.util.Spliterators$IteratorSpliterator.forEachRemaining(Spliterators.java:1801)
	at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:484)
	at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:474)
	at java.base/java.util.stream.ForEachOps$ForEachOp.evaluateSequential(ForEachOps.java:150)
	at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateSequential(ForEachOps.java:173)
	at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
	at java.base/java.util.stream.ReferencePipeline.forEach(ReferencePipeline.java:497)
	at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor$NodeExecutor.lambda$executeRecursively$3(HierarchicalTestExecutor.java:120)
	at org.junit.platform.engine.support.hierarchical.SingleTestExecutor.executeSafely(SingleTestExecutor.java:66)
	at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor$NodeExecutor.executeRecursively(HierarchicalTestExecutor.java:108)
	at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor$NodeExecutor.execute(HierarchicalTestExecutor.java:79)
	at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:55)
	at org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:43)
	at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:170)
	at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:154)
	at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:90)
	at com.intellij.junit5.JUnit5IdeaTestRunner.startRunnerWithArgs(JUnit5IdeaTestRunner.java:69)
	at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:47)
	at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242)
	at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)

Kommentar

Ermitteln Sie die Anzahl der Methodenzeilen

Betrachtet man die Implementierung von javassist.bytecode.MethodInfo # getLineNumber, Es scheint, dass der an das Argument übergebene numerische Wert an die folgende Methode übergeben wird. https://github.com/jboss-javassist/javassist/blob/rel_3_25_0_ga/src/main/javassist/bytecode/LineNumberAttribute.java#L77 Es scheint, dass es nur beurteilt wird, indem man es in einer Schleife dreht und überschreitet, also Wir übergeben "Integer.MIN_VALUE" und "Integer.MAX_VALUE".

Anfang und Ende sind

100: public void method(){
101: //Start ist hier die Anzahl der Zeilen
102: //
103: //Ende ist die Anzahl der Zeilen hier
104: }

Da 103-102 = 2 ist, wird es als Methode mit 1 hinzugefügten und 3 Zeilen behandelt.

Über Javassist

Ältere Versionen von Javassist folgen nicht der neueren Java-Version, machen Sie sie also so neu wie möglich.

Referenzmaterial

Ich möchte die Liste der Klassen unter dem Paket \ -Qiita rekursiv durchsuchen Javassist-Memo \ (Hishidamas Javassist-Memo )

Recommended Posts

[Java] Vereinigen Sie diese NG, wenn eine Methode mit einer großen Anzahl von Zeilen mithilfe von schwarzer Magie erkannt wird
[Java] Es kann glücklich sein, wenn der Rückgabewert der Methode, die null zurückgibt, Optional <> ist
Selbst in Java möchte ich true mit == 1 && a == 2 && a == 3 ausgeben (graue Magie, die weniger schwarze Magie ist)
Erstellen Sie mit der Datei Ruby on Rails seeds.rb eine große Anzahl von Datensätzen mit einem einzigen Befehl
[Read Effective Java] Kapitel 2 Punkt 2 "Betrachten Sie einen Builder, wenn Sie mit einer großen Anzahl von Konstruktorparametern konfrontiert werden."
[Java] Listenmethode, die bestimmt, ob ein bestimmtes Objekt enthalten ist
Ist die von Ihnen verwendete Version von Elasticsearch mit Java 11 kompatibel?
Deklarieren Sie eine Methode mit einem Java-Rückgabewert mit dem Rückgabewert-Datentyp
Finden Sie heraus, ob es eine Schriftart gibt, die Japanisch (Hiragana, Katakana, Kanji) mit AWS Lambda + Java verwenden kann