Skip to content

Commit 71b930e

Browse files
committed
LAB-3 Реализация standalone приложения
1 parent a2b386b commit 71b930e

File tree

9 files changed

+403
-61
lines changed

9 files changed

+403
-61
lines changed

build.gradle.kts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,12 @@ dependencies {
1818
testImplementation(platform("org.junit:junit-bom:5.10.0"))
1919
testImplementation("org.junit.jupiter:junit-jupiter")
2020
testRuntimeOnly("org.junit.platform:junit-platform-launcher")
21+
22+
implementation("org.slf4j:slf4j-api:2.0.16")
23+
implementation("ch.qos.logback:logback-classic:1.5.13")
24+
compileOnly("org.projectlombok:lombok:1.18.36")
25+
annotationProcessor("org.projectlombok:lombok:1.18.36")
26+
implementation("com.fasterxml.jackson.core:jackson-databind:2.0.1")
2127
}
2228

2329
tasks.test {

result.json

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"maxDepthOfInheritance" : 2,
3+
"averageInheritanceDepth" : 1.5,
4+
"averageOverriddenMethods" : 1.0,
5+
"averageFieldCount" : 0.7,
6+
"averageAbcScore" : 0.7234898064243891
7+
}
Lines changed: 77 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,91 @@
11
package org.example;
22

3-
import org.example.visitor.ClassPrinter;
3+
import com.fasterxml.jackson.databind.ObjectMapper;
4+
import com.fasterxml.jackson.databind.SerializationFeature;
5+
import lombok.extern.slf4j.Slf4j;
6+
import org.example.dto.Result;
7+
import org.example.model.JarMetrics;
8+
import org.example.visitor.CustomClassVisitor;
49
import org.objectweb.asm.ClassReader;
510

611
import java.io.IOException;
7-
import java.util.Enumeration;
12+
import java.nio.file.Paths;
813
import java.util.jar.JarEntry;
914
import java.util.jar.JarFile;
1015

16+
@Slf4j
1117
public class Example {
1218

1319
public static void main(String[] args) throws IOException {
14-
// var printer = new ByteCodePrinter();
15-
// printer.printBubbleSortBytecode();
16-
try (JarFile sampleJar = new JarFile("src/main/resources/sample.jar")) {
17-
Enumeration<JarEntry> enumeration = sampleJar.entries();
18-
19-
while (enumeration.hasMoreElements()) {
20-
JarEntry entry = enumeration.nextElement();
21-
if (entry.getName().endsWith(".class")) {
22-
ClassPrinter cp = new ClassPrinter();
23-
ClassReader cr = new ClassReader(sampleJar.getInputStream(entry));
24-
cr.accept(cp, 0);
25-
}
26-
}
20+
if (args.length != 2) {
21+
log.error("Ошибка чтения аргументов");
22+
System.exit(1);
2723
}
24+
25+
var jarPath = args[0];
26+
var outputFileName = args[1];
27+
28+
var result = processJarFile(jarPath);
29+
writeResultAsJson(result, outputFileName);
30+
}
31+
32+
private static Result processJarFile(String jarFilePath) throws IOException {
33+
var jarMetrics = new JarMetrics();
34+
35+
try (var jarFile = new JarFile(jarFilePath)) {
36+
jarFile.stream()
37+
.filter(e -> e.getName().endsWith(".class"))
38+
.forEach(entry -> processClass(entry, jarFile, jarMetrics));
39+
}
40+
41+
jarMetrics.calculateMetrics();
42+
43+
var stringBuilder = new StringBuilder()
44+
.append("Максимальная глубина наследования: ").append(jarMetrics.getMaxDepthOfInheritance()).append('\n')
45+
.append("Средняя глубина наследования: ").append(jarMetrics.getAverageInheritanceDepth()).append('\n')
46+
.append("Метрика ABC: ").append(jarMetrics.getAverageAbcScore()).append('\n')
47+
.append("Сколичество переопределенных методов: ").append(jarMetrics.getAverageOverriddenMethods()).append('\n')
48+
.append("Среднее количество полей в классе: ").append(jarMetrics.getAverageFieldCount());
49+
50+
log.info(stringBuilder.toString());
51+
52+
return buildFinalResult(jarMetrics);
53+
}
54+
55+
private static void processClass(JarEntry entry, JarFile jarFile, JarMetrics metrics) {
56+
try {
57+
var reader = new ClassReader(jarFile.getInputStream(entry));
58+
reader.accept(new CustomClassVisitor(metrics), 0);
59+
} catch (IOException e) {
60+
throw new RuntimeException("Ошибка чтения файла. Причина: " + entry.getName(), e);
61+
}
62+
}
63+
64+
private static Result buildFinalResult(JarMetrics metrics) {
65+
return Result.builder()
66+
.maxDepthOfInheritance(metrics.getMaxDepthOfInheritance())
67+
.averageInheritanceDepth(metrics.getAverageInheritanceDepth())
68+
.averageOverriddenMethods(metrics.getAverageOverriddenMethods())
69+
.averageFieldCount(metrics.getAverageFieldCount())
70+
.averageAbcScore(metrics.getAverageAbcScore())
71+
.build();
72+
}
73+
74+
private static void writeResultAsJson(Object result, String outputFileName) throws IOException {
75+
var mapper = new ObjectMapper().enable(SerializationFeature.INDENT_OUTPUT);
76+
77+
var file = Paths.get(outputFileName).toFile();
78+
79+
if (file.getParentFile() != null && !file.getParentFile().exists()) {
80+
file.getParentFile().mkdirs();
81+
}
82+
83+
if (!file.exists()) {
84+
file.createNewFile();
85+
}
86+
87+
mapper.writeValue(file, result);
88+
89+
log.info("Метрики сохранены в файл: {}", file.getAbsolutePath());
2890
}
2991
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
package org.example.dto;
2+
3+
import lombok.Builder;
4+
import lombok.Getter;
5+
import lombok.ToString;
6+
7+
@Getter
8+
@Builder
9+
@ToString
10+
public class Result {
11+
private int maxDepthOfInheritance;
12+
private double averageInheritanceDepth;
13+
private double averageOverriddenMethods;
14+
private double averageFieldCount;
15+
private double averageAbcScore;
16+
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
package org.example.model;
2+
3+
import lombok.Getter;
4+
import lombok.Setter;
5+
6+
import java.util.ArrayList;
7+
import java.util.List;
8+
9+
@Getter
10+
@Setter
11+
public class ClassMetrics {
12+
13+
private String name;
14+
private String parentClassName;
15+
private int fieldCount;
16+
private final List<MethodMetrics> methodMetrics = new ArrayList<>();
17+
18+
public void addMetrics(MethodMetrics methodMetrics) {
19+
this.methodMetrics.add(methodMetrics);
20+
}
21+
22+
@Getter
23+
@Setter
24+
public static class MethodMetrics {
25+
private String signature;
26+
private final ABCMetric abcMetric = new ABCMetric();
27+
28+
public void setMetricValue(double metricValue) {
29+
this.getAbcMetric().setMetricValue(metricValue);
30+
}
31+
32+
@Getter
33+
@Setter
34+
public static class ABCMetric {
35+
private long assignments;
36+
private long branches;
37+
private long conditions;
38+
private double metricValue;
39+
}
40+
}
41+
}
Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
package org.example.model;
2+
3+
import java.util.HashMap;
4+
import java.util.HashSet;
5+
import java.util.List;
6+
import java.util.Map;
7+
import java.util.Set;
8+
9+
public class JarMetrics {
10+
11+
private final Map<String, String> classParent = new HashMap<>();
12+
private final Map<String, List<String>> classMethods = new HashMap<>();
13+
private final Map<String, Integer> classMaxDepth = new HashMap<>();
14+
private final Map<String, Integer> classOverriddenMethods = new HashMap<>();
15+
private final Map<String, ClassMetrics> classMetrics = new HashMap<>();
16+
17+
public void addParent(String className, String parent) {
18+
classParent.put(className, parent);
19+
}
20+
21+
public void addMethods(String className, List<String> methodSignatures) {
22+
classMethods.put(className, methodSignatures);
23+
}
24+
25+
public void addClassMetrics(ClassMetrics classMetrics) {
26+
this.classMetrics.put(classMetrics.getName(), classMetrics);
27+
}
28+
29+
public void calculateMetrics() {
30+
classParent.keySet().forEach(this::calculateDepth);
31+
classMethods.forEach(this::calculateOverriddenMethods);
32+
}
33+
34+
public int getMaxDepthOfInheritance() {
35+
return classMaxDepth.values().stream()
36+
.max(Integer::compareTo)
37+
.orElse(0);
38+
}
39+
40+
public double getAverageInheritanceDepth() {
41+
return classMaxDepth.values().stream()
42+
.mapToInt(Integer::intValue)
43+
.average()
44+
.orElse(0.0);
45+
}
46+
47+
public double getAverageAbcScore() {
48+
return classMetrics.values().stream()
49+
.flatMap(c -> c.getMethodMetrics().stream())
50+
.mapToDouble(mm -> mm.getAbcMetric().getMetricValue())
51+
.average()
52+
.orElse(0.0);
53+
}
54+
55+
public double getAverageOverriddenMethods() {
56+
return classOverriddenMethods.values().stream()
57+
.mapToInt(Integer::intValue)
58+
.average()
59+
.orElse(0.0);
60+
}
61+
62+
public double getAverageFieldCount() {
63+
return classMetrics.values().stream()
64+
.mapToInt(ClassMetrics::getFieldCount)
65+
.average()
66+
.orElse(0.0);
67+
}
68+
69+
private void calculateDepth(String className) {
70+
classMaxDepth.put(className, computeDepth(className));
71+
}
72+
73+
private int computeDepth(String className) {
74+
int depth = 0;
75+
var current = className;
76+
77+
while (classParent.containsKey(current)) {
78+
depth++;
79+
current = classParent.get(current);
80+
}
81+
82+
return depth;
83+
}
84+
85+
private void calculateOverriddenMethods(String className, List<String> methods) {
86+
var inherited = collectInheritedMethods(className);
87+
var count = methods.stream().filter(inherited::contains).count();
88+
classOverriddenMethods.put(className, (int) count);
89+
}
90+
91+
private Set<String> collectInheritedMethods(String className) {
92+
var parent = classParent.get(className);
93+
Set<String> inherited = new HashSet<>();
94+
95+
while (parent != null) {
96+
var parentMethods = classMethods.get(parent);
97+
if (parentMethods != null) {
98+
inherited.addAll(parentMethods);
99+
}
100+
parent = classParent.get(parent);
101+
}
102+
103+
return inherited;
104+
}
105+
}

src/main/java/org/example/visitor/ClassPrinter.java

Lines changed: 0 additions & 46 deletions
This file was deleted.

0 commit comments

Comments
 (0)