Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
[![Review Assignment Due Date](https://classroom.github.com/assets/deadline-readme-button-22041afd0340ce965d47ae6ef1cefeee28c7c493a6346c4f15d667ab976d596c.svg)](https://classroom.github.com/a/9A22t-SS)
Разработать standalone приложение, которое имеет следующие возможности:

Принимает на вход проект в виде .jar файла
Expand Down
9 changes: 9 additions & 0 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,13 @@ dependencies {

tasks.test {
useJUnitPlatform()
}

tasks.jar {
manifest {
attributes["Main-Class"] = "org.example.Main"
}

from(configurations.runtimeClasspath.get().map { if (it.isDirectory) it else zipTree(it) })
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
}
64 changes: 64 additions & 0 deletions src/main/java/org/example/Main.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
package org.example;

import org.example.analyzer.JarMetricsAnalyzer;
import org.example.model.Metrics;
import org.example.output.ConsoleOutputFormatter;
import org.example.output.JsonOutputFormatter;

import java.io.File;
import java.io.IOException;

public class Main {

public static void main(String[] args) {
if (args.length == 0) {
System.exit(1);
}

String jarFilePath = args[0];
String outputFilePath = null;

for (int i = 1; i < args.length; i++) {
if (args[i].equals("--output") && i + 1 < args.length) {
outputFilePath = args[i + 1];
i++;
}
}

File jarFile = new File(jarFilePath);
if (!jarFile.exists()) {
System.err.println("Ошибка: JAR файл не найден: " + jarFilePath);
System.exit(1);
}

if (!jarFile.isFile()) {
System.err.println("Ошибка: Указанный путь не является файлом: " + jarFilePath);
System.exit(1);
}

try {
System.out.println("Анализ JAR файла: " + jarFilePath);

JarMetricsAnalyzer analyzer = new JarMetricsAnalyzer();
Metrics metrics = analyzer.analyze(jarFilePath);

ConsoleOutputFormatter consoleFormatter = new ConsoleOutputFormatter();
consoleFormatter.print(metrics);

if (outputFilePath != null) {
JsonOutputFormatter jsonFormatter = new JsonOutputFormatter();
jsonFormatter.writeToFile(metrics, outputFilePath);
System.out.println("Метрики сохранены в файл: " + outputFilePath);
}

} catch (IOException e) {
System.err.println("Ошибка при анализе JAR файла: " + e.getMessage());
e.printStackTrace();
System.exit(1);
} catch (Exception e) {
System.err.println("Неожиданная ошибка: " + e.getMessage());
e.printStackTrace();
System.exit(1);
}
}
}
29 changes: 29 additions & 0 deletions src/main/java/org/example/analyzer/JarMetricsAnalyzer.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package org.example.analyzer;

import org.example.model.Metrics;

import java.io.IOException;
import java.util.Enumeration;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;

public class JarMetricsAnalyzer {

public Metrics analyze(String jarFilePath) throws IOException {
MetricsCollector collector = new MetricsCollector();

try (JarFile jarFile = new JarFile(jarFilePath)) {
Enumeration<JarEntry> entries = jarFile.entries();

while (entries.hasMoreElements()) {
JarEntry entry = entries.nextElement();

if (entry.getName().endsWith(".class")) {
collector.processClass(jarFile.getInputStream(entry));
}
}
}

return collector.calculateMetrics();
}
}
77 changes: 77 additions & 0 deletions src/main/java/org/example/analyzer/MetricsCollector.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
package org.example.analyzer;

import org.example.model.ClassInfo;
import org.example.model.Metrics;
import org.example.model.MethodInfo;
import org.example.visitor.*;
import org.objectweb.asm.ClassReader;

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

public class MetricsCollector {
private final Map<String, ClassInfo> classInfoMap;
private final InheritanceVisitor inheritanceVisitor;

public MetricsCollector() {
this.classInfoMap = new HashMap<>();
this.inheritanceVisitor = new InheritanceVisitor(classInfoMap);
}

public void processClass(InputStream classStream) throws IOException {
ClassReader classReader = new ClassReader(classStream);
String className = classReader.getClassName();

ClassInfo classInfo = classInfoMap.computeIfAbsent(className,
k -> new ClassInfo(className, classReader.getSuperName()));

ClassMetricsVisitor metricsVisitor = new ClassMetricsVisitor(classInfo, classInfoMap);
classReader.accept(metricsVisitor, 0);

classInfo.setOverriddenMethodsCount(metricsVisitor.getOverriddenMethodsCount());
}

public Metrics calculateMetrics() {
Metrics metrics = new Metrics();

if (classInfoMap.isEmpty()) {
return metrics;
}

int totalInheritanceDepth = 0;
int maxInheritanceDepth = 0;
int totalAbcMetric = 0;
int totalFields = 0;
int totalOverriddenMethods = 0;
int classCount = classInfoMap.size();

for (ClassInfo classInfo : classInfoMap.values()) {
int depth = inheritanceVisitor.calculateInheritanceDepth(classInfo.getName());
classInfo.setInheritanceDepth(depth);
totalInheritanceDepth += depth;
maxInheritanceDepth = Math.max(maxInheritanceDepth, depth);

for (MethodInfo method : classInfo.getMethods()) {
totalAbcMetric += method.getAssignmentCount();
}

totalFields += classInfo.getFieldCount();

totalOverriddenMethods += classInfo.getOverriddenMethodsCount();
}

metrics.setMaxInheritanceDepth(maxInheritanceDepth);
metrics.setAvgInheritanceDepth((double) totalInheritanceDepth / classCount);
metrics.setTotalAbcMetric(totalAbcMetric);
metrics.setAvgOverriddenMethods((double) totalOverriddenMethods / classCount);
metrics.setAvgFieldsPerClass((double) totalFields / classCount);

return metrics;
}

public Map<String, ClassInfo> getClassInfoMap() {
return classInfoMap;
}
}
73 changes: 73 additions & 0 deletions src/main/java/org/example/model/ClassInfo.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
package org.example.model;

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

public class ClassInfo {
private final String name;
private final String superName;
private final List<MethodInfo> methods;
private int fieldCount;
private int inheritanceDepth;
private int overriddenMethodsCount;

public ClassInfo(String name, String superName) {
this.name = name;
this.superName = superName;
this.methods = new ArrayList<>();
this.fieldCount = 0;
this.inheritanceDepth = -1;
this.overriddenMethodsCount = 0;
}

public String getName() {
return name;
}

public String getSuperName() {
return superName;
}

public List<MethodInfo> getMethods() {
return methods;
}

public void addMethod(MethodInfo method) {
this.methods.add(method);
}

public int getFieldCount() {
return fieldCount;
}

public void setFieldCount(int fieldCount) {
this.fieldCount = fieldCount;
}

public int getInheritanceDepth() {
return inheritanceDepth;
}

public void setInheritanceDepth(int inheritanceDepth) {
this.inheritanceDepth = inheritanceDepth;
}

public int getOverriddenMethodsCount() {
return overriddenMethodsCount;
}

public void setOverriddenMethodsCount(int overriddenMethodsCount) {
this.overriddenMethodsCount = overriddenMethodsCount;
}

@Override
public String toString() {
return "ClassInfo{" +
"name='" + name + '\'' +
", superName='" + superName + '\'' +
", methods=" + methods.size() +
", fieldCount=" + fieldCount +
", inheritanceDepth=" + inheritanceDepth +
'}';
}
}
46 changes: 46 additions & 0 deletions src/main/java/org/example/model/MethodInfo.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package org.example.model;

public class MethodInfo {
private final String name;
private final String descriptor;
private int assignmentCount;

public MethodInfo(String name, String descriptor) {
this.name = name;
this.descriptor = descriptor;
this.assignmentCount = 0;
}

public String getName() {
return name;
}

public String getDescriptor() {
return descriptor;
}

public int getAssignmentCount() {
return assignmentCount;
}

public void setAssignmentCount(int assignmentCount) {
this.assignmentCount = assignmentCount;
}

public void incrementAssignmentCount() {
this.assignmentCount++;
}

public String getSignature() {
return name + descriptor;
}

@Override
public String toString() {
return "MethodInfo{" +
"name='" + name + '\'' +
", descriptor='" + descriptor + '\'' +
", assignmentCount=" + assignmentCount +
'}';
}
}
68 changes: 68 additions & 0 deletions src/main/java/org/example/model/Metrics.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
package org.example.model;

public class Metrics {
private int maxInheritanceDepth;
private double avgInheritanceDepth;
private int totalAbcMetric;
private double avgOverriddenMethods;
private double avgFieldsPerClass;

public Metrics() {
this.maxInheritanceDepth = 0;
this.avgInheritanceDepth = 0.0;
this.totalAbcMetric = 0;
this.avgOverriddenMethods = 0.0;
this.avgFieldsPerClass = 0.0;
}

public int getMaxInheritanceDepth() {
return maxInheritanceDepth;
}

public void setMaxInheritanceDepth(int maxInheritanceDepth) {
this.maxInheritanceDepth = maxInheritanceDepth;
}

public double getAvgInheritanceDepth() {
return avgInheritanceDepth;
}

public void setAvgInheritanceDepth(double avgInheritanceDepth) {
this.avgInheritanceDepth = avgInheritanceDepth;
}

public int getTotalAbcMetric() {
return totalAbcMetric;
}

public void setTotalAbcMetric(int totalAbcMetric) {
this.totalAbcMetric = totalAbcMetric;
}

public double getAvgOverriddenMethods() {
return avgOverriddenMethods;
}

public void setAvgOverriddenMethods(double avgOverriddenMethods) {
this.avgOverriddenMethods = avgOverriddenMethods;
}

public double getAvgFieldsPerClass() {
return avgFieldsPerClass;
}

public void setAvgFieldsPerClass(double avgFieldsPerClass) {
this.avgFieldsPerClass = avgFieldsPerClass;
}

@Override
public String toString() {
return "Metrics{" +
"maxInheritanceDepth=" + maxInheritanceDepth +
", avgInheritanceDepth=" + avgInheritanceDepth +
", totalAbcMetric=" + totalAbcMetric +
", avgOverriddenMethods=" + avgOverriddenMethods +
", avgFieldsPerClass=" + avgFieldsPerClass +
'}';
}
}
Loading