├── jdbl-core ├── lib │ ├── jcov.jar │ └── jcov_file_saver.jar ├── src │ ├── test │ │ ├── resources │ │ │ ├── calc │ │ │ │ ├── Calc.class │ │ │ │ ├── Main.class │ │ │ │ ├── inst │ │ │ │ │ ├── Calc.class │ │ │ │ │ ├── Main.class │ │ │ │ │ ├── report │ │ │ │ │ │ ├── allclasses-frame.html │ │ │ │ │ │ ├── package-frame.html │ │ │ │ │ │ ├── overview-frame.html │ │ │ │ │ │ ├── index.html │ │ │ │ │ │ ├── overview-summary.html │ │ │ │ │ │ ├── package-summary.html │ │ │ │ │ │ ├── Calc.html │ │ │ │ │ │ └── Main.html │ │ │ │ │ ├── result.xml │ │ │ │ │ └── template.xml │ │ │ │ └── template.xml │ │ │ ├── classes │ │ │ │ └── calc │ │ │ │ │ ├── Init.class │ │ │ │ │ ├── StaticCl.class │ │ │ │ │ ├── Calculator.class │ │ │ │ │ ├── CalculatorB.class │ │ │ │ │ ├── CalculatorInt.class │ │ │ │ │ ├── MainCalculator.class │ │ │ │ │ └── IncorrectFileNameException.class │ │ │ ├── jcov │ │ │ │ ├── input │ │ │ │ │ ├── Calculator.class │ │ │ │ │ ├── CalculatorB.class │ │ │ │ │ ├── CalculatorInt.class │ │ │ │ │ ├── MainCalculator.class │ │ │ │ │ └── IncorrectFileNameException.class │ │ │ │ ├── output │ │ │ │ │ ├── Calculator.class │ │ │ │ │ ├── CalculatorB.class │ │ │ │ │ ├── CalculatorInt.class │ │ │ │ │ ├── MainCalculator.class │ │ │ │ │ └── IncorrectFileNameException.class │ │ │ │ └── report.xml │ │ │ ├── jars │ │ │ │ └── org.jacoco.agent-0.7.9.jar │ │ │ ├── log4j.properties │ │ │ └── coverage │ │ │ │ ├── result_jcov.xml │ │ │ │ └── report_jacoco.xml │ │ └── java │ │ │ └── se │ │ │ └── kth │ │ │ └── castor │ │ │ └── jdbl │ │ │ ├── adapter │ │ │ └── CustomClassReaderTest.java │ │ │ ├── coverage │ │ │ ├── JCovReportReaderTest.java │ │ │ ├── JacocoReportReaderTest.java │ │ │ ├── UsageAnalysisTest.java │ │ │ └── JCovCoverageTest.java │ │ │ └── util │ │ │ ├── JarUtilsTest.java │ │ │ └── MyFileUtilsTest.java │ └── main │ │ ├── java │ │ └── se │ │ │ └── kth │ │ │ └── castor │ │ │ └── jdbl │ │ │ ├── coverage │ │ │ ├── UsageAnalyzer.java │ │ │ ├── CoverageToolEnum.java │ │ │ ├── UsageStatusEnum.java │ │ │ ├── JVMClassesCoveredSingleton.java │ │ │ ├── Instrumentation.java │ │ │ ├── UsageAnalysis.java │ │ │ ├── JVMClassCoverage.java │ │ │ └── JCovReportReader.java │ │ │ ├── deptree │ │ │ ├── Visitor.java │ │ │ ├── Parser.java │ │ │ ├── InputType.java │ │ │ ├── ParseException.java │ │ │ ├── VisitException.java │ │ │ ├── StandardTextVisitor.java │ │ │ ├── AbstractLineBasedParser.java │ │ │ ├── AbstractTextVisitor.java │ │ │ ├── TextParser.java │ │ │ └── AbstractParser.java │ │ │ ├── debloat │ │ │ ├── DebloatTypeEnum.java │ │ │ ├── MethodExceptionThrower.java │ │ │ ├── AbstractMethodDebloat.java │ │ │ ├── EntryPointMethodDebloat.java │ │ │ └── ConservativeMethodDebloat.java │ │ │ ├── util │ │ │ ├── ClassFileType.java │ │ │ ├── JarWithDeps.java │ │ │ ├── CmdExec.java │ │ │ └── ZipUtils.java │ │ │ ├── load │ │ │ ├── LoaderCollector.java │ │ │ ├── AbstractClassLoader.java │ │ │ ├── EntryPointClassLoader.java │ │ │ └── TestBasedClassLoader.java │ │ │ ├── adapter │ │ │ ├── CustomClassReader.java │ │ │ └── ClassAdapter.java │ │ │ ├── test │ │ │ ├── TestResult.java │ │ │ ├── StackLine.java │ │ │ └── TestRunner.java │ │ │ ├── reflection │ │ │ └── MethodInvoker.java │ │ │ └── callgraph │ │ │ └── ClassVisitor.java │ │ └── resources │ │ └── log4j.properties └── pom.xml ├── jdbl-app └── src │ └── main │ ├── resources │ └── parameters.txt │ └── java │ └── se │ └── kth │ └── castor │ └── jdbl │ ├── Debloat.java │ └── DebloatBuilder.java ├── jdbl-agent ├── src │ └── main │ │ ├── resources │ │ └── META-INF │ │ │ └── MANIFEST.MF │ │ └── java │ │ └── se │ │ └── kth │ │ └── castor │ │ └── jdbl │ │ └── agent │ │ ├── CallAdvice.java │ │ └── Agent.java └── pom.xml ├── jdbl-maven-plugin ├── src │ ├── it │ │ └── dummy-project │ │ │ └── src │ │ │ ├── main │ │ │ └── java │ │ │ │ ├── calc │ │ │ │ ├── CalculatorB.java │ │ │ │ ├── CalculatorInt.java │ │ │ │ ├── StaticCl.java │ │ │ │ ├── MainCalculator.java │ │ │ │ ├── Calculator.java │ │ │ │ └── other │ │ │ │ │ └── CalculatorNew.java │ │ │ │ ├── bag │ │ │ │ ├── MainBag.java │ │ │ │ └── BagClass.java │ │ │ │ ├── reflection │ │ │ │ ├── BaseInterface.java │ │ │ │ ├── BaseClass.java │ │ │ │ └── ConcreteClass.java │ │ │ │ ├── neverused │ │ │ │ ├── OtherClass.java │ │ │ │ ├── Main2.java │ │ │ │ └── UntestedClass.java │ │ │ │ ├── interfaces │ │ │ │ ├── Alarm.java │ │ │ │ ├── Application.java │ │ │ │ ├── Vehicle.java │ │ │ │ ├── Car.java │ │ │ │ ├── Motorbike.java │ │ │ │ └── MultiAlarmCar.java │ │ │ │ ├── annotations │ │ │ │ ├── JsonSerializationException.java │ │ │ │ ├── Init.java │ │ │ │ ├── JsonSerializable.java │ │ │ │ ├── JsonElement.java │ │ │ │ ├── Person.java │ │ │ │ └── ObjectToJsonConverter.java │ │ │ │ ├── Calc.java │ │ │ │ ├── Main.java │ │ │ │ ├── lambda │ │ │ │ ├── package-info.java │ │ │ │ ├── OrderMatcher.java │ │ │ │ ├── OrderMatcherWithFees.java │ │ │ │ └── LambdaScoping.java │ │ │ │ ├── singleton │ │ │ │ └── Singleton.java │ │ │ │ ├── enums │ │ │ │ └── CropState.java │ │ │ │ ├── defaultmethods │ │ │ │ ├── MyTradingApi.java │ │ │ │ └── TradingApi.java │ │ │ │ └── common │ │ │ │ └── Order.java │ │ │ └── test │ │ │ └── java │ │ │ ├── bag │ │ │ └── BagClassTest.java │ │ │ ├── calc │ │ │ ├── other │ │ │ │ └── CalculatorNewTest.java │ │ │ └── CalculatorTest.java │ │ │ ├── enums │ │ │ └── CropStateTest.java │ │ │ ├── reflection │ │ │ └── BaseClassTest.java │ │ │ ├── annotations │ │ │ └── ObjectToJsonConverterTest.java │ │ │ ├── interfaces │ │ │ └── ApplicationTest.java │ │ │ └── defaultmethods │ │ │ └── TestDefaultMethodUsage.java │ └── main │ │ ├── resources │ │ └── log4j.properties │ │ └── java │ │ └── se │ │ └── kth │ │ └── castor │ │ └── jdbl │ │ └── plugin │ │ ├── AbstractDebloatMojo.java │ │ ├── ConservativeDebloatMojo.java │ │ └── EntryPointDebloatMojo.java └── jdbl-run.sh ├── .github ├── ISSUE_TEMPLATE.md ├── PULL_REQUEST_TEMPLATE.md └── workflows │ └── build.yml ├── LICENSE ├── .gitignore └── .img └── logo.svg /jdbl-core/lib/jcov.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ASSERT-KTH/jdbl/HEAD/jdbl-core/lib/jcov.jar -------------------------------------------------------------------------------- /jdbl-app/src/main/resources/parameters.txt: -------------------------------------------------------------------------------- 1 | -input I -output O -class C -method M -parameters P 2 | 3 | -------------------------------------------------------------------------------- /jdbl-core/lib/jcov_file_saver.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ASSERT-KTH/jdbl/HEAD/jdbl-core/lib/jcov_file_saver.jar -------------------------------------------------------------------------------- /jdbl-agent/src/main/resources/META-INF/MANIFEST.MF: -------------------------------------------------------------------------------- 1 | Manifest-Version: 1.0 2 | Premain-Class: se.kth.castor.jdbl.agent.Agent 3 | -------------------------------------------------------------------------------- /jdbl-core/src/test/resources/calc/Calc.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ASSERT-KTH/jdbl/HEAD/jdbl-core/src/test/resources/calc/Calc.class -------------------------------------------------------------------------------- /jdbl-core/src/test/resources/calc/Main.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ASSERT-KTH/jdbl/HEAD/jdbl-core/src/test/resources/calc/Main.class -------------------------------------------------------------------------------- /jdbl-core/src/test/resources/calc/inst/Calc.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ASSERT-KTH/jdbl/HEAD/jdbl-core/src/test/resources/calc/inst/Calc.class -------------------------------------------------------------------------------- /jdbl-core/src/test/resources/calc/inst/Main.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ASSERT-KTH/jdbl/HEAD/jdbl-core/src/test/resources/calc/inst/Main.class -------------------------------------------------------------------------------- /jdbl-core/src/test/resources/classes/calc/Init.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ASSERT-KTH/jdbl/HEAD/jdbl-core/src/test/resources/classes/calc/Init.class -------------------------------------------------------------------------------- /jdbl-core/src/test/resources/classes/calc/StaticCl.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ASSERT-KTH/jdbl/HEAD/jdbl-core/src/test/resources/classes/calc/StaticCl.class -------------------------------------------------------------------------------- /jdbl-core/src/test/resources/jcov/input/Calculator.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ASSERT-KTH/jdbl/HEAD/jdbl-core/src/test/resources/jcov/input/Calculator.class -------------------------------------------------------------------------------- /jdbl-core/src/test/resources/classes/calc/Calculator.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ASSERT-KTH/jdbl/HEAD/jdbl-core/src/test/resources/classes/calc/Calculator.class -------------------------------------------------------------------------------- /jdbl-core/src/test/resources/jcov/input/CalculatorB.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ASSERT-KTH/jdbl/HEAD/jdbl-core/src/test/resources/jcov/input/CalculatorB.class -------------------------------------------------------------------------------- /jdbl-core/src/test/resources/jcov/output/Calculator.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ASSERT-KTH/jdbl/HEAD/jdbl-core/src/test/resources/jcov/output/Calculator.class -------------------------------------------------------------------------------- /jdbl-core/src/test/resources/jcov/output/CalculatorB.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ASSERT-KTH/jdbl/HEAD/jdbl-core/src/test/resources/jcov/output/CalculatorB.class -------------------------------------------------------------------------------- /jdbl-core/src/test/resources/classes/calc/CalculatorB.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ASSERT-KTH/jdbl/HEAD/jdbl-core/src/test/resources/classes/calc/CalculatorB.class -------------------------------------------------------------------------------- /jdbl-core/src/test/resources/classes/calc/CalculatorInt.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ASSERT-KTH/jdbl/HEAD/jdbl-core/src/test/resources/classes/calc/CalculatorInt.class -------------------------------------------------------------------------------- /jdbl-core/src/test/resources/jars/org.jacoco.agent-0.7.9.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ASSERT-KTH/jdbl/HEAD/jdbl-core/src/test/resources/jars/org.jacoco.agent-0.7.9.jar -------------------------------------------------------------------------------- /jdbl-core/src/test/resources/jcov/input/CalculatorInt.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ASSERT-KTH/jdbl/HEAD/jdbl-core/src/test/resources/jcov/input/CalculatorInt.class -------------------------------------------------------------------------------- /jdbl-core/src/test/resources/jcov/input/MainCalculator.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ASSERT-KTH/jdbl/HEAD/jdbl-core/src/test/resources/jcov/input/MainCalculator.class -------------------------------------------------------------------------------- /jdbl-core/src/test/resources/jcov/output/CalculatorInt.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ASSERT-KTH/jdbl/HEAD/jdbl-core/src/test/resources/jcov/output/CalculatorInt.class -------------------------------------------------------------------------------- /jdbl-core/src/test/resources/jcov/output/MainCalculator.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ASSERT-KTH/jdbl/HEAD/jdbl-core/src/test/resources/jcov/output/MainCalculator.class -------------------------------------------------------------------------------- /jdbl-core/src/test/resources/classes/calc/MainCalculator.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ASSERT-KTH/jdbl/HEAD/jdbl-core/src/test/resources/classes/calc/MainCalculator.class -------------------------------------------------------------------------------- /jdbl-maven-plugin/src/it/dummy-project/src/main/java/calc/CalculatorB.java: -------------------------------------------------------------------------------- 1 | package calc; 2 | 3 | public abstract class CalculatorB implements CalculatorInt { 4 | 5 | 6 | 7 | } 8 | -------------------------------------------------------------------------------- /jdbl-core/src/test/resources/jcov/input/IncorrectFileNameException.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ASSERT-KTH/jdbl/HEAD/jdbl-core/src/test/resources/jcov/input/IncorrectFileNameException.class -------------------------------------------------------------------------------- /jdbl-core/src/test/resources/jcov/output/IncorrectFileNameException.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ASSERT-KTH/jdbl/HEAD/jdbl-core/src/test/resources/jcov/output/IncorrectFileNameException.class -------------------------------------------------------------------------------- /jdbl-core/src/main/java/se/kth/castor/jdbl/coverage/UsageAnalyzer.java: -------------------------------------------------------------------------------- 1 | package se.kth.castor.jdbl.coverage; 2 | 3 | public interface UsageAnalyzer 4 | { 5 | UsageAnalysis analyzeUsages(); 6 | } 7 | -------------------------------------------------------------------------------- /jdbl-core/src/main/java/se/kth/castor/jdbl/deptree/Visitor.java: -------------------------------------------------------------------------------- 1 | package se.kth.castor.jdbl.deptree; 2 | 3 | public interface Visitor 4 | { 5 | void visit(Node tree) throws VisitException; 6 | } 7 | -------------------------------------------------------------------------------- /jdbl-core/src/test/resources/classes/calc/IncorrectFileNameException.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ASSERT-KTH/jdbl/HEAD/jdbl-core/src/test/resources/classes/calc/IncorrectFileNameException.class -------------------------------------------------------------------------------- /jdbl-maven-plugin/src/it/dummy-project/src/main/java/calc/CalculatorInt.java: -------------------------------------------------------------------------------- 1 | package calc; 2 | 3 | public interface CalculatorInt { 4 | int sum(); 5 | 6 | int sub(); 7 | 8 | int mul(); 9 | } 10 | -------------------------------------------------------------------------------- /jdbl-core/src/main/java/se/kth/castor/jdbl/deptree/Parser.java: -------------------------------------------------------------------------------- 1 | package se.kth.castor.jdbl.deptree; 2 | 3 | import java.io.Reader; 4 | 5 | public interface Parser 6 | { 7 | Node parse(Reader reader) throws ParseException; 8 | } 9 | -------------------------------------------------------------------------------- /jdbl-maven-plugin/src/it/dummy-project/src/main/java/bag/MainBag.java: -------------------------------------------------------------------------------- 1 | package bag; 2 | 3 | public class MainBag { 4 | public static void main(String[] args) { 5 | BagClass baseClass = new BagClass(); 6 | baseClass.main(); 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /jdbl-maven-plugin/src/it/dummy-project/src/main/java/reflection/BaseInterface.java: -------------------------------------------------------------------------------- 1 | package reflection; 2 | 3 | public interface BaseInterface { 4 | 5 | public int interFaceInt = 0; 6 | 7 | void method1(); 8 | int method2(String str); 9 | 10 | } 11 | -------------------------------------------------------------------------------- /jdbl-maven-plugin/src/it/dummy-project/src/main/java/calc/StaticCl.java: -------------------------------------------------------------------------------- 1 | package calc; 2 | 3 | public class StaticCl { 4 | public static final int A = 10; 5 | 6 | 7 | // public static final int A; 8 | // 9 | // static { 10 | // A = 10; 11 | // } 12 | } 13 | -------------------------------------------------------------------------------- /jdbl-maven-plugin/src/it/dummy-project/src/main/java/neverused/OtherClass.java: -------------------------------------------------------------------------------- 1 | package neverused; 2 | 3 | public class OtherClass { 4 | 5 | public int returnFive(){ 6 | return 5; 7 | } 8 | 9 | public int returnTen(){ 10 | return 10; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /jdbl-maven-plugin/src/it/dummy-project/src/main/java/neverused/Main2.java: -------------------------------------------------------------------------------- 1 | package neverused; 2 | 3 | public class Main2 { 4 | 5 | int n; 6 | 7 | public Main2(int n) { 8 | this.n = n; 9 | } 10 | 11 | public int pow() { 12 | return n * n; 13 | } 14 | 15 | } 16 | -------------------------------------------------------------------------------- /jdbl-maven-plugin/jdbl-run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | #echo "----- INSTALLING THE jdbl PLUGIN -----" 4 | cd .. 5 | mvn clean 6 | mvn install -DskipTests=true 7 | 8 | 9 | echo "----- RUNNING THE EXPERIMENTS ON dummy-project -----" 10 | cd jdbl-maven-plugin/src/it/dummy-project 11 | mvn clean package -e 12 | -------------------------------------------------------------------------------- /jdbl-maven-plugin/src/it/dummy-project/src/test/java/bag/BagClassTest.java: -------------------------------------------------------------------------------- 1 | package bag; 2 | 3 | import org.junit.Test; 4 | 5 | public class BagClassTest { 6 | 7 | BagClass bagClass = new BagClass(); 8 | 9 | @Test 10 | public void testBagTester() { 11 | bagClass.main(); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /jdbl-agent/src/main/java/se/kth/castor/jdbl/agent/CallAdvice.java: -------------------------------------------------------------------------------- 1 | package se.kth.castor.jdbl.agent; 2 | 3 | import net.bytebuddy.asm.Advice; 4 | 5 | class CallAdvice { 6 | @Advice.OnMethodEnter() 7 | static void enter(@Advice.Origin("#t,#m,#d") String origin) { 8 | Agent.calledMethods.add(origin); 9 | } 10 | } -------------------------------------------------------------------------------- /jdbl-maven-plugin/src/it/dummy-project/src/main/java/interfaces/Alarm.java: -------------------------------------------------------------------------------- 1 | package interfaces; 2 | 3 | public interface Alarm { 4 | 5 | default String turnAlarmOn() { 6 | return "Turning the alarm on."; 7 | } 8 | 9 | default String turnAlarmOff() { 10 | return "Turning the alarm off."; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /jdbl-core/src/main/java/se/kth/castor/jdbl/deptree/InputType.java: -------------------------------------------------------------------------------- 1 | package se.kth.castor.jdbl.deptree; 2 | 3 | public enum InputType 4 | { 5 | TEXT { 6 | @Override 7 | public Parser newParser() 8 | { 9 | return new TextParser(); 10 | } 11 | }; 12 | 13 | public abstract Parser newParser(); 14 | } 15 | -------------------------------------------------------------------------------- /jdbl-maven-plugin/src/it/dummy-project/src/main/java/annotations/JsonSerializationException.java: -------------------------------------------------------------------------------- 1 | package annotations; 2 | 3 | public class JsonSerializationException extends RuntimeException { 4 | 5 | private static final long serialVersionUID = 1L; 6 | 7 | public JsonSerializationException(String message) { 8 | super(message); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /jdbl-maven-plugin/src/it/dummy-project/src/test/java/calc/other/CalculatorNewTest.java: -------------------------------------------------------------------------------- 1 | package calc.other; 2 | 3 | import org.junit.Test; 4 | 5 | public class CalculatorNewTest 6 | { 7 | 8 | @Test 9 | public void sum() 10 | { 11 | CalculatorNew calculatorNew = new CalculatorNew(4, 3); 12 | calculatorNew.sum(); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /jdbl-maven-plugin/src/it/dummy-project/src/main/java/calc/MainCalculator.java: -------------------------------------------------------------------------------- 1 | package calc; 2 | 3 | public class MainCalculator { 4 | 5 | public static void main(String[] args) { 6 | CalculatorInt calculatorInt = new Calculator(Integer.parseInt(args[0]), Integer.parseInt(args[1])); 7 | System.out.println("The sum is: " + calculatorInt.sum()); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /jdbl-core/src/main/resources/log4j.properties: -------------------------------------------------------------------------------- 1 | # Set root logger level to DEBUG and its only appender to A1. 2 | log4j.rootLogger=DEBUG, A1 3 | 4 | # A1 is set to be a ConsoleAppender. 5 | log4j.appender.A1=org.apache.log4j.ConsoleAppender 6 | 7 | # A1 uses PatternLayout. 8 | log4j.appender.A1.layout=org.apache.log4j.PatternLayout 9 | log4j.appender.A1.layout.ConversionPattern=%-4r [%t] %-5p %c %x - %m%n -------------------------------------------------------------------------------- /jdbl-core/src/test/resources/log4j.properties: -------------------------------------------------------------------------------- 1 | # Set root logger level to DEBUG and its only appender to A1. 2 | log4j.rootLogger=DEBUG, A1 3 | 4 | # A1 is set to be a ConsoleAppender. 5 | log4j.appender.A1=org.apache.log4j.ConsoleAppender 6 | 7 | # A1 uses PatternLayout. 8 | log4j.appender.A1.layout=org.apache.log4j.PatternLayout 9 | log4j.appender.A1.layout.ConversionPattern=%-4r [%t] %-5p %c %x - %m%n -------------------------------------------------------------------------------- /jdbl-maven-plugin/src/it/dummy-project/src/main/java/annotations/Init.java: -------------------------------------------------------------------------------- 1 | package annotations; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.lang.annotation.Target; 7 | 8 | @Retention(RetentionPolicy.RUNTIME) 9 | @Target(ElementType.METHOD) 10 | public @interface Init 11 | { 12 | } 13 | -------------------------------------------------------------------------------- /jdbl-maven-plugin/src/main/resources/log4j.properties: -------------------------------------------------------------------------------- 1 | # Set root logger level to DEBUG and its only appender to A1. 2 | log4j.rootLogger=DEBUG, A1 3 | 4 | # A1 is set to be a ConsoleAppender. 5 | log4j.appender.A1=org.apache.log4j.ConsoleAppender 6 | 7 | # A1 uses PatternLayout. 8 | log4j.appender.A1.layout=org.apache.log4j.PatternLayout 9 | log4j.appender.A1.layout.ConversionPattern=%-4r [%t] %-5p %c %x - %m%n -------------------------------------------------------------------------------- /jdbl-maven-plugin/src/it/dummy-project/src/main/java/Calc.java: -------------------------------------------------------------------------------- 1 | public class Calc 2 | { 3 | 4 | int a; 5 | int b; 6 | 7 | public Calc(final int a, final int b) 8 | { 9 | this.a = a; 10 | this.b = b; 11 | } 12 | 13 | public int sum (){ 14 | return a + b; 15 | } 16 | 17 | public int rest (){ 18 | return a - b; 19 | } 20 | 21 | 22 | } 23 | -------------------------------------------------------------------------------- /jdbl-maven-plugin/src/it/dummy-project/src/main/java/Main.java: -------------------------------------------------------------------------------- 1 | public class Main 2 | { 3 | public static void main(String[] args) 4 | { 5 | 6 | Calc calc = new Calc(2,5); 7 | int result = calc.sum(); 8 | System.out.println("The sum is" + result); 9 | } 10 | 11 | private static int anotherSum(final int i, final int i1) 12 | { 13 | return i + i1; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /jdbl-maven-plugin/src/it/dummy-project/src/main/java/annotations/JsonSerializable.java: -------------------------------------------------------------------------------- 1 | package annotations; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.lang.annotation.Target; 7 | 8 | @Retention(RetentionPolicy.RUNTIME) 9 | @Target(ElementType.TYPE) 10 | public @interface JsonSerializable 11 | { 12 | } 13 | -------------------------------------------------------------------------------- /jdbl-core/src/main/java/se/kth/castor/jdbl/debloat/DebloatTypeEnum.java: -------------------------------------------------------------------------------- 1 | package se.kth.castor.jdbl.debloat; 2 | 3 | /** 4 | * The debloat strategies supported by this plugin. 5 | */ 6 | public enum DebloatTypeEnum 7 | { 8 | TEST_DEBLOAT, 9 | ENTRY_POINT_DEBLOAT, 10 | CONSERVATIVE_DEBLOAT; 11 | 12 | @Override 13 | public String toString() 14 | { 15 | return this.name(); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /jdbl-maven-plugin/src/it/dummy-project/src/main/java/lambda/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | *

Lambda

3 | * 4 | * Example code for using lambda expressions in Java 8. See the {@link TestLambdaUsage} unit test class for usage. 5 | *

6 | * More info in the 7 | * Java 8 tutorial. 8 | * 9 | * @author gazbert 10 | */ 11 | package lambda; 12 | -------------------------------------------------------------------------------- /jdbl-maven-plugin/src/it/dummy-project/src/main/java/annotations/JsonElement.java: -------------------------------------------------------------------------------- 1 | package annotations; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.lang.annotation.Target; 7 | 8 | @Retention(RetentionPolicy.RUNTIME) 9 | @Target(ElementType.FIELD) 10 | public @interface JsonElement 11 | { 12 | String key() default ""; 13 | } 14 | -------------------------------------------------------------------------------- /jdbl-maven-plugin/src/it/dummy-project/src/main/java/singleton/Singleton.java: -------------------------------------------------------------------------------- 1 | package singleton; 2 | 3 | public class Singleton 4 | { 5 | private static final Singleton instance = new Singleton(); 6 | 7 | //private constructor to avoid client applications to use constructor 8 | private Singleton() 9 | { 10 | } 11 | 12 | public static Singleton getInstance() 13 | { 14 | return instance; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /jdbl-app/src/main/java/se/kth/castor/jdbl/Debloat.java: -------------------------------------------------------------------------------- 1 | package se.kth.castor.jdbl; 2 | 3 | import java.io.File; 4 | import java.io.IOException; 5 | 6 | public interface Debloat { 7 | 8 | /** 9 | * Debloat a jar file via static and dynamic analysis of execution traces. 10 | * 11 | * @param input The jar file to be debloated. 12 | * @return A debloated jar file. 13 | */ 14 | File debloat(File input) throws IOException; 15 | } 16 | -------------------------------------------------------------------------------- /jdbl-maven-plugin/src/it/dummy-project/src/test/java/enums/CropStateTest.java: -------------------------------------------------------------------------------- 1 | package enums; 2 | 3 | import org.junit.Test; 4 | 5 | import static org.hamcrest.CoreMatchers.is; 6 | import static org.junit.Assert.*; 7 | 8 | public class CropStateTest { 9 | @Test 10 | public void getByData() { 11 | for (CropState cropState : CropState.values()) { 12 | assertThat(CropState.getByData(cropState.getData()), is(cropState)); 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /jdbl-core/src/main/java/se/kth/castor/jdbl/coverage/CoverageToolEnum.java: -------------------------------------------------------------------------------- 1 | package se.kth.castor.jdbl.coverage; 2 | 3 | public enum CoverageToolEnum 4 | { 5 | JCOV("JCov"), 6 | YAJTA("Yajta"), 7 | JACOCO("JaCoCo"), 8 | JVM_CLASS_LOADER("JVM"); 9 | 10 | private String tool; 11 | 12 | CoverageToolEnum(String tool) 13 | { 14 | this.tool = tool; 15 | } 16 | 17 | public String getName() 18 | { 19 | return tool; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /jdbl-core/src/main/java/se/kth/castor/jdbl/util/ClassFileType.java: -------------------------------------------------------------------------------- 1 | package se.kth.castor.jdbl.util; 2 | 3 | /** 4 | * The debloat strategies supported by this plugin. 5 | */ 6 | public enum ClassFileType 7 | { 8 | ANNOTATION, 9 | ENUM, 10 | INTERFACE, 11 | CONSTANT, 12 | CLASS, 13 | EXCEPTION, 14 | SINGLETON, 15 | CLASS_ABSTRACT, 16 | UNKNOWN; 17 | 18 | @Override 19 | public String toString() 20 | { 21 | return this.name(); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /jdbl-maven-plugin/src/it/dummy-project/src/main/java/neverused/UntestedClass.java: -------------------------------------------------------------------------------- 1 | package neverused; 2 | 3 | public class UntestedClass { 4 | 5 | int a; 6 | int b; 7 | 8 | public UntestedClass(int a, int b) { 9 | this.a = a; 10 | this.b = b; 11 | } 12 | 13 | public int sum() { 14 | return a + b; 15 | } 16 | 17 | public int sub() { 18 | return a - b; 19 | } 20 | 21 | public int mul() { 22 | return a * b; 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /jdbl-maven-plugin/src/it/dummy-project/src/main/java/interfaces/Application.java: -------------------------------------------------------------------------------- 1 | package interfaces; 2 | 3 | public class Application { 4 | 5 | public static void main(String[] args) { 6 | 7 | Vehicle car = new Car("BMW"); 8 | System.out.println(car.getBrand()); 9 | System.out.println(car.speedUp()); 10 | System.out.println(car.slowDown()); 11 | System.out.println(car.turnAlarmOn()); 12 | System.out.println(car.turnAlarmOff()); 13 | System.out.println(Vehicle.getHorsePower(2500, 480)); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /jdbl-maven-plugin/src/it/dummy-project/src/main/java/interfaces/Vehicle.java: -------------------------------------------------------------------------------- 1 | package interfaces; 2 | 3 | public interface Vehicle { 4 | 5 | String getBrand(); 6 | 7 | String speedUp(); 8 | 9 | String slowDown(); 10 | 11 | default String turnAlarmOn() { 12 | return "Turning the vehice alarm on."; 13 | } 14 | 15 | default String turnAlarmOff() { 16 | return "Turning the vehicle alarm off."; 17 | } 18 | 19 | static int getHorsePower(int rpm, int torque) { 20 | return (rpm * torque) / 5252; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /jdbl-core/src/main/java/se/kth/castor/jdbl/coverage/UsageStatusEnum.java: -------------------------------------------------------------------------------- 1 | package se.kth.castor.jdbl.coverage; 2 | 3 | public enum UsageStatusEnum 4 | { 5 | USED_CLASS("UsedClass"), 6 | PRESERVED_CLASS("PreservedClass"), 7 | BLOATED_CLASS("BloatedClass"), 8 | USED_METHOD("UsedMethod"), 9 | BLOATED_METHOD("BloatedMethod"); 10 | 11 | private String status; 12 | 13 | UsageStatusEnum(String status) 14 | { 15 | this.status = status; 16 | } 17 | 18 | public String getName() 19 | { 20 | return status; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /jdbl-maven-plugin/src/it/dummy-project/src/main/java/interfaces/Car.java: -------------------------------------------------------------------------------- 1 | package interfaces; 2 | 3 | public class Car implements Vehicle { 4 | 5 | private final String brand; 6 | 7 | public Car(String brand) { 8 | this.brand = brand; 9 | } 10 | 11 | @Override 12 | public String getBrand() { 13 | return brand; 14 | } 15 | 16 | @Override 17 | public String speedUp() { 18 | return "The car is speeding up."; 19 | } 20 | 21 | @Override 22 | public String slowDown() { 23 | return "The car is slowing down."; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /jdbl-core/src/test/resources/calc/inst/report/allclasses-frame.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | coverage report 5 | 6 | 7 | 8 | All classes 9 | 10 | 11 | 15 | 16 |
12 | Calc  67% (2/3)
13 | Main  33% (1/3)
14 |
17 | 18 | 19 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | Make sure the title of the issue explains the problem you are having. Also, the description of the issue must clearly explain what is broken, not what you want us to implement. Go through this checklist and make sure you answer "YES" to all points: 2 | 3 | * You have all pre-requisites listed in README.md installed 4 | * You are sure that you are not reporting a duplicate (search all issues) 5 | * You say "is broken" or "doesn't work" in the title 6 | * You tell us what you are trying to do 7 | * You explain the results you are getting 8 | * You suggest an alternative result you would like to see 9 | -------------------------------------------------------------------------------- /jdbl-maven-plugin/src/it/dummy-project/src/main/java/interfaces/Motorbike.java: -------------------------------------------------------------------------------- 1 | package interfaces; 2 | 3 | public class Motorbike implements Vehicle { 4 | 5 | private final String brand; 6 | 7 | public Motorbike(String brand) { 8 | this.brand = brand; 9 | } 10 | 11 | @Override 12 | public String getBrand() { 13 | return brand; 14 | } 15 | 16 | @Override 17 | public String speedUp() { 18 | return "The motorbike is speeding up."; 19 | } 20 | 21 | @Override 22 | public String slowDown() { 23 | return "The motorbike is slowing down."; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /jdbl-core/src/main/java/se/kth/castor/jdbl/deptree/ParseException.java: -------------------------------------------------------------------------------- 1 | package se.kth.castor.jdbl.deptree; 2 | 3 | public class ParseException extends Exception 4 | { 5 | private static final long serialVersionUID = -5422097493752660982L; 6 | 7 | public ParseException() 8 | { 9 | } 10 | 11 | public ParseException(String message) 12 | { 13 | super(message); 14 | } 15 | 16 | public ParseException(Throwable cause) 17 | { 18 | super(cause); 19 | } 20 | 21 | public ParseException(String message, Throwable cause) 22 | { 23 | super(message, cause); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /jdbl-core/src/main/java/se/kth/castor/jdbl/deptree/VisitException.java: -------------------------------------------------------------------------------- 1 | package se.kth.castor.jdbl.deptree; 2 | 3 | public class VisitException extends Exception 4 | { 5 | private static final long serialVersionUID = -8947246553563244540L; 6 | 7 | public VisitException() 8 | { 9 | } 10 | 11 | public VisitException(String message) 12 | { 13 | super(message); 14 | } 15 | 16 | public VisitException(Throwable cause) 17 | { 18 | super(cause); 19 | } 20 | 21 | public VisitException(String message, Throwable cause) 22 | { 23 | super(message, cause); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /jdbl-maven-plugin/src/it/dummy-project/src/main/java/calc/Calculator.java: -------------------------------------------------------------------------------- 1 | package calc; 2 | 3 | public class Calculator extends CalculatorB { 4 | 5 | int a; 6 | int b; 7 | 8 | public Calculator(int a, int b) { 9 | this.a = a; 10 | this.b = b; 11 | } 12 | 13 | @Override 14 | public int sum() { 15 | return a + b; 16 | } 17 | 18 | @Override 19 | public int sub() { 20 | return a - b; 21 | } 22 | 23 | @Override 24 | public int mul() { 25 | return a * b; 26 | } 27 | 28 | public int other() { 29 | return StaticCl.A; 30 | } 31 | 32 | } 33 | -------------------------------------------------------------------------------- /jdbl-maven-plugin/src/it/dummy-project/src/test/java/calc/CalculatorTest.java: -------------------------------------------------------------------------------- 1 | package calc; 2 | 3 | import org.junit.Ignore; 4 | import org.junit.Before; 5 | import org.junit.Test; 6 | 7 | import static org.junit.Assert.assertEquals; 8 | 9 | public class CalculatorTest { 10 | 11 | CalculatorInt calculatorInt; 12 | 13 | @Before 14 | public void setUp() { 15 | calculatorInt = new Calculator(2, 3); 16 | } 17 | 18 | @Test 19 | public void testSum() { 20 | assertEquals(5, calculatorInt.sum()); 21 | } 22 | 23 | @Test 24 | public void testOther() { 25 | assertEquals(10, ((Calculator) calculatorInt).other()); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /jdbl-maven-plugin/src/it/dummy-project/src/main/java/bag/BagClass.java: -------------------------------------------------------------------------------- 1 | package bag; 2 | 3 | import org.apache.commons.collections4.Bag; 4 | import org.apache.commons.collections4.bag.HashBag; 5 | 6 | public class BagClass { 7 | 8 | public void main() { 9 | Bag bag = new HashBag<>(); 10 | 11 | //add "a" two times to the bag. 12 | bag.add("a", 2); 13 | 14 | //add "b" one time to the bag. 15 | bag.add("b"); 16 | 17 | //add "c" one time to the bag. 18 | bag.add("c"); 19 | 20 | //add "d" three times to the bag. 21 | bag.add("d", 3); 22 | 23 | System.out.println("Set of unique values from the bag: " + bag.uniqueSet()); 24 | } 25 | } -------------------------------------------------------------------------------- /jdbl-maven-plugin/src/it/dummy-project/src/main/java/calc/other/CalculatorNew.java: -------------------------------------------------------------------------------- 1 | package calc.other; 2 | 3 | import calc.CalculatorB; 4 | import calc.StaticCl; 5 | 6 | public class CalculatorNew extends CalculatorB 7 | { 8 | 9 | int a; 10 | int b; 11 | 12 | public CalculatorNew(int a, int b) { 13 | this.a = a; 14 | this.b = b; 15 | } 16 | 17 | @Override 18 | public int sum() { 19 | return a + b; 20 | } 21 | 22 | @Override 23 | public int sub() { 24 | return a - b; 25 | } 26 | 27 | @Override 28 | public int mul() { 29 | return a * b; 30 | } 31 | 32 | public int other() { 33 | return StaticCl.A; 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /jdbl-core/src/test/resources/calc/inst/report/package-frame.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | coverage report 5 | 6 | 7 | 8 |

9 |   50% (3/6)
10 |

11 | All classes 12 | 13 | 14 | 18 | 19 |
15 | Calc  67% (2/3)
16 | Main  33% (1/3)
17 |
20 | 21 | 22 | -------------------------------------------------------------------------------- /jdbl-maven-plugin/src/it/dummy-project/src/main/java/reflection/BaseClass.java: -------------------------------------------------------------------------------- 1 | package reflection; 2 | 3 | public class BaseClass { 4 | 5 | public int baseInt; 6 | 7 | private static void method3() { 8 | System.out.println("Method3"); 9 | } 10 | 11 | public String method7(String input) { 12 | System.out.println(input); 13 | return input; 14 | } 15 | 16 | public static int method5() { 17 | System.out.println("Method5"); 18 | return 0; 19 | } 20 | 21 | private static void method6() { 22 | System.out.println("Method6"); 23 | } 24 | 25 | // inner public class 26 | public class BaseClassInnerClass { 27 | } 28 | 29 | //member public enum 30 | public enum BaseClassMemberEnum { 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /jdbl-core/src/test/resources/calc/inst/report/overview-frame.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | coverage report 5 | 6 | 7 | 8 | Coverage report
9 |
10 | 11 | 12 | 16 | 17 |
13 | Overview
14 | All classes 15 |
18 | 19 | 20 | 21 | 22 | 23 | 26 | 27 |
All packages
24 |
25 |
28 | 29 | 30 | -------------------------------------------------------------------------------- /jdbl-core/src/main/java/se/kth/castor/jdbl/load/LoaderCollector.java: -------------------------------------------------------------------------------- 1 | package se.kth.castor.jdbl.load; 2 | 3 | import java.util.Iterator; 4 | import java.util.Vector; 5 | 6 | public class LoaderCollector 7 | { 8 | public static Iterator list(ClassLoader classLoader) throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException 9 | { 10 | Class CL_class = classLoader.getClass(); 11 | while (CL_class != ClassLoader.class) { 12 | CL_class = CL_class.getSuperclass(); 13 | } 14 | java.lang.reflect.Field ClassLoader_classes_field = CL_class 15 | .getDeclaredField("classes"); 16 | ClassLoader_classes_field.setAccessible(true); 17 | Vector classes = (Vector) ClassLoader_classes_field.get(classLoader); 18 | return classes.iterator(); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /jdbl-core/src/main/java/se/kth/castor/jdbl/coverage/JVMClassesCoveredSingleton.java: -------------------------------------------------------------------------------- 1 | package se.kth.castor.jdbl.coverage; 2 | 3 | import java.util.Set; 4 | 5 | import org.apache.log4j.LogManager; 6 | import org.apache.log4j.Logger; 7 | 8 | public enum JVMClassesCoveredSingleton 9 | { 10 | INSTANCE; 11 | 12 | private static final Logger LOGGER = LogManager.getLogger(JVMClassesCoveredSingleton.class.getName()); 13 | 14 | private Set classesLoaded; 15 | 16 | protected void setClassesLoaded(Set classesLoaded) 17 | { 18 | this.classesLoaded = classesLoaded; 19 | } 20 | 21 | public Set getClassesLoaded() 22 | { 23 | return this.classesLoaded; 24 | } 25 | 26 | public void printClassesLoaded() 27 | { 28 | this.classesLoaded.forEach(s -> LOGGER.info("Loaded: " + s)); 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /jdbl-core/src/main/java/se/kth/castor/jdbl/deptree/StandardTextVisitor.java: -------------------------------------------------------------------------------- 1 | package se.kth.castor.jdbl.deptree; 2 | 3 | /** 4 | * Generates an output that is identical to the output generated by the following Maven command: 5 | *
mvn dependency:tree -DoutputType=text -Dtokens=standard
6 | */ 7 | public class StandardTextVisitor extends AbstractTextVisitor 8 | { 9 | @Override 10 | public String getTreeSymbols(Node node) 11 | { 12 | if (node == node.getParent().getLastChildNode()) { 13 | return "\\- "; 14 | } else { 15 | return "+- "; 16 | } 17 | } 18 | 19 | @Override 20 | public String getParentTreeSymbols(Node node) 21 | { 22 | if (node == node.getParent().getLastChildNode()) { 23 | return " "; 24 | } else { 25 | return "| "; 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /jdbl-maven-plugin/src/it/dummy-project/src/test/java/reflection/BaseClassTest.java: -------------------------------------------------------------------------------- 1 | package reflection; 2 | 3 | import org.junit.Assert; 4 | import org.junit.Test; 5 | 6 | import java.lang.reflect.InvocationTargetException; 7 | import java.lang.reflect.Method; 8 | 9 | public class BaseClassTest { 10 | 11 | 12 | // @Test 13 | // public void invokePrivateMethod() 14 | // throws ClassNotFoundException, InvocationTargetException, IllegalAccessException, NoSuchMethodException { 15 | // ConcreteClass concreteClass = new ConcreteClass(); 16 | // //invoking private method 17 | // Method method = Class.forName("reflection.ConcreteClass").getDeclaredMethod("method6", String.class); 18 | // method.setAccessible(true); 19 | // String output = (String) method.invoke(concreteClass, "Some input"); //prints "Method3" 20 | // Assert.assertEquals(output, "Some input"); 21 | // } 22 | 23 | 24 | } -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | Many thanks for your contribution, we truly appreciate it. We will appreciate it even more, if you make sure that you can say "YES" to each point in this short checklist: 2 | 3 | * You made a small amount of changes (less than 100 lines, less than 10 files) 4 | * You made changes related to only one bug (create separate PRs for separate problems, or leave TODOs) 5 | * You are ready to defend your changes (there will be a code review) 6 | * You don't touch what you don't understand 7 | * You ran the build locally and it passed 8 | * Title begins with the issue's number, then a short title 9 | * Description begins with the issue's number, then enumerates the changes - summarized - in bullet points 10 | * Description does not contain GitHub keywords (https://help.github.com/articles/closing-issues-using-keywords). 11 | * You ran the build locally and it passed (see `.travis.yml` for all checks performed on PRs) 12 | -------------------------------------------------------------------------------- /jdbl-core/src/test/java/se/kth/castor/jdbl/adapter/CustomClassReaderTest.java: -------------------------------------------------------------------------------- 1 | package se.kth.castor.jdbl.adapter; 2 | 3 | import org.junit.Test; 4 | 5 | import static org.junit.jupiter.api.Assertions.assertFalse; 6 | import static org.junit.jupiter.api.Assertions.assertTrue; 7 | 8 | public class CustomClassReaderTest 9 | { 10 | CustomClassReader ccr; 11 | 12 | @Test 13 | public void testIsInterface() 14 | { 15 | ccr = new CustomClassReader("java.lang.Appendable"); 16 | assertTrue(ccr.isInterface()); 17 | ccr = new CustomClassReader("java.lang.Character"); 18 | assertFalse(ccr.isInterface()); 19 | } 20 | 21 | @Test 22 | public void testIsException() 23 | { 24 | ccr = new CustomClassReader("java.io.FileNotFoundException"); 25 | assertTrue(ccr.isException()); 26 | ccr = new CustomClassReader("java.io.Bits"); 27 | assertFalse(ccr.isException()); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /jdbl-maven-plugin/src/it/dummy-project/src/main/java/interfaces/MultiAlarmCar.java: -------------------------------------------------------------------------------- 1 | package interfaces; 2 | 3 | public class MultiAlarmCar implements Vehicle, Alarm { 4 | 5 | private final String brand; 6 | 7 | public MultiAlarmCar(String brand) { 8 | this.brand = brand; 9 | } 10 | 11 | @Override 12 | public String getBrand() { 13 | return brand; 14 | } 15 | 16 | @Override 17 | public String speedUp() { 18 | return "The motorbike is speeding up."; 19 | } 20 | 21 | @Override 22 | public String slowDown() { 23 | return "The mootorbike is slowing down."; 24 | } 25 | 26 | @Override 27 | public String turnAlarmOn() { 28 | return Vehicle.super.turnAlarmOn() + " " + Alarm.super.turnAlarmOn(); 29 | } 30 | 31 | @Override 32 | public String turnAlarmOff() { 33 | return Vehicle.super.turnAlarmOff() + " " + Alarm.super.turnAlarmOff(); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /jdbl-core/src/main/java/se/kth/castor/jdbl/debloat/MethodExceptionThrower.java: -------------------------------------------------------------------------------- 1 | package se.kth.castor.jdbl.debloat; 2 | 3 | import org.objectweb.asm.MethodVisitor; 4 | import org.objectweb.asm.Opcodes; 5 | 6 | public class MethodExceptionThrower extends MethodVisitor 7 | { 8 | private final MethodVisitor target; 9 | 10 | public MethodExceptionThrower(MethodVisitor methodVisitor) 11 | { 12 | super(Opcodes.ASM8, null); 13 | this.target = methodVisitor; 14 | } 15 | 16 | @Override 17 | public void visitCode() 18 | { 19 | target.visitCode(); 20 | target.visitTypeInsn(Opcodes.NEW, "java/lang/UnsupportedOperationException"); 21 | target.visitInsn(Opcodes.DUP); 22 | target.visitMethodInsn(Opcodes.INVOKESPECIAL, "java/lang/UnsupportedOperationException", "", "()V", false); 23 | target.visitInsn(Opcodes.ATHROW); 24 | target.visitMaxs(2, 0); 25 | target.visitEnd(); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /jdbl-maven-plugin/src/it/dummy-project/src/test/java/annotations/ObjectToJsonConverterTest.java: -------------------------------------------------------------------------------- 1 | package annotations; 2 | 3 | import org.junit.Test; 4 | 5 | import static org.junit.Assert.*; 6 | 7 | public class ObjectToJsonConverterTest { 8 | 9 | @Test 10 | public void givenObjectNotSerializedThenExceptionThrown() throws JsonSerializationException { 11 | Object object = new Object(); 12 | ObjectToJsonConverter serializer = new ObjectToJsonConverter(); 13 | assertThrows(JsonSerializationException.class, () -> { 14 | serializer.convertToJson(object); 15 | }); 16 | } 17 | 18 | @Test 19 | public void givenObjectSerializedThenTrueReturned() throws JsonSerializationException { 20 | Person person = new Person("soufiane", "cheouati", "34"); 21 | ObjectToJsonConverter serializer = new ObjectToJsonConverter(); 22 | String jsonString = serializer.convertToJson(person); 23 | assertEquals("{\"personAge\":\"34\",\"firstName\":\"Soufiane\",\"lastName\":\"Cheouati\"}", jsonString); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /jdbl-core/src/main/java/se/kth/castor/jdbl/util/JarWithDeps.java: -------------------------------------------------------------------------------- 1 | package se.kth.castor.jdbl.util; 2 | 3 | public class JarWithDeps 4 | { 5 | private static JarWithDeps single_instance = null; 6 | 7 | private String name; 8 | private String path; 9 | 10 | private JarWithDeps(String name, String path) 11 | { 12 | this.name = name; 13 | this.path = path; 14 | } 15 | 16 | public static JarWithDeps setInstance(String name, String path) 17 | { 18 | if (single_instance == null) { 19 | single_instance = new JarWithDeps(name, path); 20 | } 21 | 22 | return single_instance; 23 | } 24 | 25 | public static JarWithDeps getInstance() 26 | { 27 | if (single_instance == null) { 28 | System.out.println("Error, jar-with-dependencies not found."); 29 | } 30 | 31 | return single_instance; 32 | } 33 | 34 | public String getName() 35 | { 36 | return name; 37 | } 38 | 39 | public String getPath() 40 | { 41 | return path; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /jdbl-core/src/test/java/se/kth/castor/jdbl/coverage/JCovReportReaderTest.java: -------------------------------------------------------------------------------- 1 | package se.kth.castor.jdbl.coverage; 2 | 3 | import java.io.File; 4 | import java.io.IOException; 5 | 6 | import org.junit.After; 7 | import org.junit.Before; 8 | import org.junit.Test; 9 | import org.xml.sax.SAXException; 10 | 11 | import javax.xml.parsers.ParserConfigurationException; 12 | import static org.junit.jupiter.api.Assertions.assertEquals; 13 | 14 | public class JCovReportReaderTest 15 | { 16 | @Test 17 | public void getUsedClassesAndMethods() throws ParserConfigurationException, IOException, SAXException 18 | { 19 | JCovReportReader r = new JCovReportReader(); 20 | final File xmlJacocoReport = new File("src/test/resources/coverage/result_jcov.xml"); 21 | UsageAnalysis observed = r.getUsedClassesAndMethods(xmlJacocoReport); 22 | System.out.println(observed.toString()); 23 | assertEquals(2, observed.getAnalysis().size()); 24 | assertEquals(2, observed.getAnalysis().get("calc/Calc").size()); 25 | assertEquals(true, observed.getAnalysis().containsKey("calc/Main")); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 CASTOR Software Research Centre (www.castor.kth.se) 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /jdbl-core/src/test/java/se/kth/castor/jdbl/coverage/JacocoReportReaderTest.java: -------------------------------------------------------------------------------- 1 | package se.kth.castor.jdbl.coverage; 2 | 3 | import java.io.File; 4 | import java.io.IOException; 5 | 6 | import org.junit.Test; 7 | import org.xml.sax.SAXException; 8 | 9 | import javax.xml.parsers.ParserConfigurationException; 10 | import static org.junit.jupiter.api.Assertions.assertEquals; 11 | 12 | public class JacocoReportReaderTest 13 | { 14 | @Test 15 | public void getUsedClassesAndMethods() throws ParserConfigurationException, IOException, SAXException 16 | { 17 | JacocoReportReader r = null; 18 | r = new JacocoReportReader(); 19 | final File xmlJacocoReport = new File("src/test/resources/coverage/report_jacoco.xml"); 20 | UsageAnalysis observed = null; 21 | observed = r.getUsedClassesAndMethods(xmlJacocoReport); 22 | assertEquals(2, observed.getAnalysis().size()); 23 | assertEquals(4, observed.getAnalysis().get("org/dummy/pa/FullyCovered").size()); 24 | assertEquals(2, observed.getAnalysis().get("org/dummy/pa/PartiallyCovered").size()); 25 | assertEquals(false, observed.getAnalysis().containsKey("org/dummy/pa/Missing")); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ### Log file 2 | *.log 3 | 4 | ### Package files 5 | *.jar 6 | !jdbl-core/src/test/resources/jars/org.jacoco.agent-0.7.9.jar 7 | !jdbl-core/lib/jcov.jar 8 | !jdbl-core/lib/jcov_file_saver.jar 9 | !jdbl-maven-plugin/src/it/dummy-project/.jdbl/dummy-project-1.0-SNAPSHOT-jar-with-dependencies-debloated.jar 10 | !jdbl-maven-plugin/src/it/dummy-project/.jdbl/dummy-project-1.0-SNAPSHOT-jar-with-dependencies-original.jar 11 | 12 | *.war 13 | *.nar 14 | *.ear 15 | *.zip 16 | *.tar.gz 17 | *.rar 18 | 19 | ### IntelliJ 20 | *.idea/ 21 | *.iml 22 | *.iws 23 | *.ipr 24 | *.ids 25 | *.orig 26 | out/ 27 | 28 | ### Git files 29 | .gitattributes 30 | 31 | ### Maven 32 | */target/ 33 | */build/ 34 | */dist/ 35 | */nbproject/ 36 | pom.xml.tag 37 | pom.xml.releaseBackup 38 | pom.xml.versionsBackup 39 | pom.xml.next 40 | release.properties 41 | dependency-reduced-pom.xml 42 | buildNumber.properties 43 | .mvn/timing.properties 44 | 45 | ### Virtual machine crash logs, 46 | # see http://www.java.com/en/download/help/error_hotspot.xml 47 | hs_err_pid* 48 | 49 | ### Checkstyle 50 | checkstyle.xml 51 | 52 | ### Others 53 | *.*~ 54 | *~ 55 | .merge_file* 56 | 57 | ### Thumbnails 58 | ._* 59 | 60 | ### Intellij 61 | .idea 62 | -------------------------------------------------------------------------------- /jdbl-core/src/main/java/se/kth/castor/jdbl/adapter/CustomClassReader.java: -------------------------------------------------------------------------------- 1 | package se.kth.castor.jdbl.adapter; 2 | 3 | import java.io.IOException; 4 | import java.io.InputStream; 5 | import java.util.logging.Level; 6 | import java.util.logging.Logger; 7 | 8 | import org.objectweb.asm.ClassReader; 9 | import org.objectweb.asm.Opcodes; 10 | 11 | public class CustomClassReader 12 | { 13 | private ClassReader cr; 14 | 15 | public CustomClassReader(InputStream classInputStream) 16 | { 17 | try { 18 | cr = new ClassReader(classInputStream); 19 | } catch (IOException e) { 20 | Logger.getLogger(CustomClassReader.class.getName()).log(Level.SEVERE, null, e); 21 | } 22 | } 23 | 24 | public CustomClassReader(String className) 25 | { 26 | try { 27 | cr = new ClassReader(className); 28 | } catch (IOException e) { 29 | Logger.getLogger(CustomClassReader.class.getName()).log(Level.SEVERE, null, e); 30 | } 31 | } 32 | 33 | public boolean isInterface() 34 | { 35 | return ((cr.getAccess() & Opcodes.ACC_INTERFACE) != 0); 36 | } 37 | 38 | public boolean isException() 39 | { 40 | return (cr.getSuperName().endsWith("Exception")); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /jdbl-core/src/main/java/se/kth/castor/jdbl/load/AbstractClassLoader.java: -------------------------------------------------------------------------------- 1 | package se.kth.castor.jdbl.load; 2 | 3 | import java.io.File; 4 | import java.net.MalformedURLException; 5 | import java.net.URL; 6 | 7 | public class AbstractClassLoader extends ClassLoader 8 | { 9 | 10 | private String classLoaderName; 11 | private String classDir; 12 | 13 | public AbstractClassLoader(String classLoaderName, String classDir) 14 | { 15 | this.classLoaderName = classLoaderName; 16 | this.classDir = classDir; 17 | } 18 | 19 | public String getClassDir() 20 | { 21 | return classDir; 22 | } 23 | 24 | @Override 25 | public URL getResource(String name) 26 | { 27 | System.out.println("[" + classLoaderName + "] getting resource: " + name); 28 | try { 29 | URL resource = new File(classDir + "/resources/" + name).toPath().toUri().toURL(); 30 | System.out.println("Path to the resource: " + resource.getPath()); 31 | return getParent().getResource(name); 32 | } catch (MalformedURLException e) { 33 | System.err.println("[" + classLoaderName + "] Error getting resource: " + name); 34 | return getParent().getResource(name); 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /jdbl-maven-plugin/src/it/dummy-project/src/main/java/reflection/ConcreteClass.java: -------------------------------------------------------------------------------- 1 | package reflection; 2 | 3 | public class ConcreteClass extends BaseClass implements BaseInterface { 4 | 5 | public int publicInt; 6 | 7 | private String privateString = "private string"; 8 | 9 | protected boolean protectedBoolean; 10 | 11 | Object defaultObject; 12 | 13 | @Override 14 | public void method1() { 15 | System.out.println("Method1 impl."); 16 | } 17 | 18 | @Override 19 | public int method2(String str) { 20 | System.out.println("Method2 impl."); 21 | return 0; 22 | } 23 | 24 | private String method6(String output) { 25 | return output; 26 | } 27 | 28 | public int method5(int i) { 29 | System.out.println("Method4 overriden."); 30 | return 0; 31 | } 32 | 33 | // inner classes 34 | public class ConcreteClassPublicClass { 35 | } 36 | 37 | private class ConcreteClassPrivateClass { 38 | } 39 | 40 | protected class ConcreteClassProtectedClass { 41 | } 42 | 43 | class ConcreteClassDefaultClass { 44 | } 45 | 46 | //member enum 47 | enum ConcreteClassDefaultEnum { 48 | } 49 | 50 | public enum ConcreteClassPublicEnum {} 51 | 52 | //member interface 53 | public interface ConcreteClassPublicInterface { 54 | } 55 | 56 | 57 | } 58 | -------------------------------------------------------------------------------- /jdbl-core/src/test/java/se/kth/castor/jdbl/util/JarUtilsTest.java: -------------------------------------------------------------------------------- 1 | package se.kth.castor.jdbl.util; 2 | 3 | import java.io.File; 4 | import java.io.IOException; 5 | import java.util.Objects; 6 | 7 | import org.junit.After; 8 | import org.junit.Before; 9 | import org.junit.Test; 10 | 11 | import static org.junit.Assert.assertFalse; 12 | 13 | public class JarUtilsTest 14 | { 15 | File jarFile; 16 | File outputDir; 17 | 18 | @Before 19 | public void setupFiles() 20 | { 21 | outputDir = new File("src/test/resources/jars/decompressed"); 22 | jarFile = new File("src/test/resources/jars/org.jacoco.agent-0.7.9.jar"); 23 | } 24 | 25 | @Test 26 | public void testThatAllJarFilesInFolderAreDecompressed() throws IOException 27 | { 28 | org.apache.commons.io.FileUtils.copyFileToDirectory(jarFile, outputDir); 29 | JarUtils.decompressJars(outputDir.getAbsolutePath()); 30 | 31 | boolean existJarFile = false; 32 | 33 | for (File f : Objects.requireNonNull(outputDir.listFiles())) { 34 | if (f.getName().endsWith(".jar")) { 35 | existJarFile = true; 36 | } 37 | assertFalse(existJarFile); 38 | } 39 | } 40 | 41 | @After 42 | public void restoreFiles() throws IOException 43 | { 44 | org.apache.commons.io.FileUtils.deleteDirectory(outputDir); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /.img/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | image/svg+xml 3 | -------------------------------------------------------------------------------- /jdbl-core/src/main/java/se/kth/castor/jdbl/load/EntryPointClassLoader.java: -------------------------------------------------------------------------------- 1 | package se.kth.castor.jdbl.load; 2 | 3 | import java.nio.file.Files; 4 | import java.nio.file.Paths; 5 | 6 | public class EntryPointClassLoader extends AbstractClassLoader 7 | { 8 | 9 | public EntryPointClassLoader(final String classLoaderName, final String classDir) 10 | { 11 | super(classLoaderName, classDir); 12 | } 13 | 14 | @Override 15 | public Class loadClass(String name) 16 | { 17 | try { 18 | System.out.println("[Parent] Loading class: " + name); 19 | return getParent().loadClass(name); 20 | } catch (ClassNotFoundException ex) { 21 | // Load this class separately 22 | try { 23 | byte[] original = Files.readAllBytes(Paths.get(getClassDir() + "/" + name.replace(".", "/") + ".class")); 24 | System.out.println("[EntryPointClassLoader] Loading class: " + name); 25 | return defineClass(name.replace("/", "."), original, 0, original.length); 26 | } catch (Exception e) { 27 | System.err.println("[EntryPointClassLoader] Error: class: " + name + " path: " + getClassDir() + "/" + name.replace(".", "/") + ".class, exception: " + e); 28 | } 29 | } 30 | System.err.println("[EntryPointClassLoader] Loading class: " + name + " failed."); 31 | return null; 32 | } 33 | } 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /jdbl-core/src/main/java/se/kth/castor/jdbl/test/TestResult.java: -------------------------------------------------------------------------------- 1 | package se.kth.castor.jdbl.test; 2 | 3 | public class TestResult 4 | { 5 | private final int totalTests; 6 | private final int failedTests; 7 | private final int errorTests; 8 | private final int skippedTests; 9 | 10 | public TestResult() 11 | { 12 | totalTests = 0; 13 | failedTests = 0; 14 | errorTests = 0; 15 | skippedTests = 0; 16 | } 17 | 18 | public TestResult(final int totalTests, final int failedTests, final int errorTests, final int skippedTests) 19 | { 20 | this.totalTests = totalTests; 21 | this.failedTests = failedTests; 22 | this.errorTests = errorTests; 23 | this.skippedTests = skippedTests; 24 | } 25 | 26 | public String getResults() 27 | { 28 | return "Tests run: " + totalTests() + ", Failures: " + failedTests() + 29 | ", Errors: " + errorTests() + ", Skipped: " + skippedTests() + "\n"; 30 | } 31 | 32 | public int totalTests() 33 | { 34 | return totalTests; 35 | } 36 | 37 | public int failedTests() 38 | { 39 | return failedTests; 40 | } 41 | 42 | public int errorTests() 43 | { 44 | return errorTests; 45 | } 46 | 47 | public int skippedTests() 48 | { 49 | return skippedTests; 50 | } 51 | 52 | @Override 53 | public String toString() 54 | { 55 | return getResults(); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /jdbl-core/src/main/java/se/kth/castor/jdbl/load/TestBasedClassLoader.java: -------------------------------------------------------------------------------- 1 | package se.kth.castor.jdbl.load; 2 | 3 | import java.io.File; 4 | import java.nio.file.Files; 5 | 6 | public class TestBasedClassLoader extends ClassLoader 7 | { 8 | private ClassLoader parent; 9 | private String testDir; 10 | private String classDir; 11 | 12 | public TestBasedClassLoader(String testDir, String classDir, ClassLoader parent) 13 | { 14 | this.testDir = testDir; 15 | this.classDir = classDir; 16 | this.parent = parent; 17 | } 18 | 19 | @Override 20 | public Class loadClass(String name) throws ClassNotFoundException 21 | { 22 | if (name.startsWith("org.junit")) { 23 | return parent.loadClass(name); 24 | } 25 | try { 26 | String qName = name.replace(".", "/") + ".class"; 27 | File byteCode = null; 28 | File potential = new File(testDir + "/" + qName); 29 | if (!potential.exists()) { 30 | potential = new File(classDir + "/" + qName); 31 | } 32 | if (potential.exists()) { 33 | byteCode = potential; 34 | } 35 | if (byteCode != null) { 36 | byte[] original = Files.readAllBytes(byteCode.toPath()); 37 | return defineClass(name.replace("/", "."), original, 0, original.length); 38 | } 39 | } catch (Exception e) { 40 | System.err.println("[TestBasedClassLoader] Error: class: " + name + ", ex: " + e); 41 | } 42 | return getParent().loadClass(name); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /jdbl-core/src/main/java/se/kth/castor/jdbl/reflection/MethodInvoker.java: -------------------------------------------------------------------------------- 1 | package se.kth.castor.jdbl.reflection; 2 | 3 | import java.lang.reflect.InvocationTargetException; 4 | import java.lang.reflect.Method; 5 | 6 | public final class MethodInvoker 7 | { 8 | /** 9 | * Invoke method with parameters in a class with a custom {@link ClassLoader}. 10 | */ 11 | @SuppressWarnings("unchecked") 12 | public static void invokeMethod(ClassLoader cl, String entryClass, String entryMethod, String entryParameters) 13 | { 14 | try { 15 | System.out.println("Entry class: " + entryClass); 16 | Class entryClassLoaded = cl.loadClass(entryClass); 17 | System.out.println("Entry class loaded: " + entryClassLoaded.getName()); 18 | Method entryMethodLoaded = entryClassLoaded.getDeclaredMethod(entryMethod, String[].class); 19 | System.out.println("Entry method loaded: " + entryMethodLoaded.getName()); 20 | 21 | if (entryParameters != null) { 22 | System.out.println("Entry param: " + entryParameters); 23 | String[] parameters = entryParameters.split(" "); 24 | System.out.println("Entry param 0: " + parameters[0]); 25 | entryMethodLoaded.invoke(null, (Object) parameters); 26 | } else { 27 | entryMethodLoaded.invoke(null, new Object[]{}); 28 | } 29 | } catch (IllegalArgumentException | NoSuchMethodException | IllegalAccessException | InvocationTargetException | 30 | ClassNotFoundException e) { 31 | System.err.println(e.toString()); 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /jdbl-core/src/test/java/se/kth/castor/jdbl/coverage/UsageAnalysisTest.java: -------------------------------------------------------------------------------- 1 | package se.kth.castor.jdbl.coverage; 2 | 3 | import java.util.Arrays; 4 | import java.util.HashSet; 5 | 6 | import org.junit.Before; 7 | import org.junit.Test; 8 | 9 | import static org.junit.jupiter.api.Assertions.assertEquals; 10 | 11 | public class UsageAnalysisTest 12 | { 13 | UsageAnalysis usageAnalysis; 14 | 15 | @Before 16 | public void setUp() 17 | { 18 | usageAnalysis = new UsageAnalysis(); 19 | usageAnalysis.addEntry("calc/Calculator", new HashSet<>(Arrays.asList("(II)V", "other()I", "sum()I"))); 20 | usageAnalysis.addEntry("calc/CalculatorB", new HashSet<>(Arrays.asList("()V"))); 21 | usageAnalysis.addEntry("calc/StaticCl", new HashSet<>()); 22 | } 23 | 24 | @Test 25 | public void removeUncoveredClasses() 26 | { 27 | usageAnalysis.removeUncoveredClasses(); 28 | System.out.println(usageAnalysis.toString()); 29 | assertEquals(2, usageAnalysis.analysis.size()); 30 | } 31 | 32 | @Test 33 | public void mergeWith() 34 | { 35 | UsageAnalysis anotherUsageAnalysis = new UsageAnalysis(); 36 | anotherUsageAnalysis.addEntry("calc/Calculator", new HashSet<>(Arrays.asList("(II)V", "other()I", "sum()I", "multiply()I"))); 37 | anotherUsageAnalysis.addEntry("calc/CalculatorA", new HashSet<>(Arrays.asList("()V"))); 38 | anotherUsageAnalysis.addEntry("calc/CalculatorB", new HashSet<>(Arrays.asList("()V"))); 39 | usageAnalysis.mergeWith(anotherUsageAnalysis); 40 | assertEquals(4, usageAnalysis.methods("calc/Calculator").size()); 41 | assertEquals(4, usageAnalysis.classes().size()); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /jdbl-maven-plugin/src/it/dummy-project/src/main/java/lambda/OrderMatcher.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2015 Gareth Jon Lynch 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy of 7 | * this software and associated documentation files (the "Software"), to deal in 8 | * the Software without restriction, including without limitation the rights to 9 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 10 | * the Software, and to permit persons to whom the Software is furnished to do so, 11 | * subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 18 | * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 19 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 20 | * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 21 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | */ 23 | 24 | package lambda; 25 | 26 | import common.Order; 27 | 28 | /** 29 | * Interface for providing query implementations for matching orders. 30 | * 31 | * @author gazbert 32 | */ 33 | public interface OrderMatcher 34 | { 35 | /** 36 | * Executes a query to see if an order matches. 37 | * 38 | * @param order the order to query. 39 | * @return true if order matched query, false otherwise. 40 | */ 41 | boolean executeQuery(Order order); 42 | } 43 | -------------------------------------------------------------------------------- /jdbl-maven-plugin/src/it/dummy-project/src/main/java/annotations/Person.java: -------------------------------------------------------------------------------- 1 | package annotations; 2 | 3 | @JsonSerializable 4 | public class Person 5 | { 6 | @JsonElement 7 | private String firstName; 8 | @JsonElement 9 | private String lastName; 10 | @JsonElement(key = "personAge") 11 | private String age; 12 | 13 | private String address; 14 | 15 | public Person(String firstName, String lastName) 16 | { 17 | super(); 18 | this.firstName = firstName; 19 | this.lastName = lastName; 20 | } 21 | 22 | public Person(String firstName, String lastName, String age) 23 | { 24 | this.firstName = firstName; 25 | this.lastName = lastName; 26 | this.age = age; 27 | } 28 | 29 | @Init 30 | private void initNames() 31 | { 32 | this.firstName = this.firstName.substring(0, 1) 33 | .toUpperCase() + this.firstName.substring(1); 34 | this.lastName = this.lastName.substring(0, 1) 35 | .toUpperCase() + this.lastName.substring(1); 36 | } 37 | 38 | public String getFirstName() 39 | { 40 | return firstName; 41 | } 42 | 43 | public void setFirstName(String firstName) 44 | { 45 | this.firstName = firstName; 46 | } 47 | 48 | public String getLastName() 49 | { 50 | return lastName; 51 | } 52 | 53 | public void setLastName(String lastName) 54 | { 55 | this.lastName = lastName; 56 | } 57 | 58 | public String getAge() 59 | { 60 | return age; 61 | } 62 | 63 | public void setAge(String age) 64 | { 65 | this.age = age; 66 | } 67 | 68 | public String getAddress() 69 | { 70 | return address; 71 | } 72 | 73 | public void setAddress(String address) 74 | { 75 | this.address = address; 76 | } 77 | 78 | } 79 | -------------------------------------------------------------------------------- /jdbl-core/src/main/java/se/kth/castor/jdbl/coverage/Instrumentation.java: -------------------------------------------------------------------------------- 1 | package se.kth.castor.jdbl.coverage; 2 | 3 | import java.io.File; 4 | 5 | /** 6 | * Information for a class instrumentation operation. 7 | */ 8 | class Instrumentation { 9 | /** 10 | * The directory of classes to be instrumented. 11 | */ 12 | private File baseDirectory; 13 | 14 | /** 15 | * The directory into which instrumented classes should be placed. 16 | */ 17 | private File instrDirectory; 18 | 19 | /** 20 | * Initialize an {@code Instrumentation} with basic data. 21 | * 22 | * @param baseDirectory The directory of classes to be instrumented. 23 | * @param instrDirectory The directory into which instrumented 24 | * classes should be placed. 25 | */ 26 | Instrumentation(final File baseDirectory, 27 | final File instrDirectory) { 28 | this.baseDirectory = baseDirectory; 29 | this.instrDirectory = instrDirectory; 30 | } 31 | 32 | /** 33 | * Get the directory of classes to be instrumented. 34 | * 35 | * @return The directory of classes to be instrumented. 36 | */ 37 | public File getBaseDirectory() { 38 | return baseDirectory; 39 | } 40 | 41 | /** 42 | * Get the directory into which instrumented classes should be placed. 43 | * 44 | * @return The directory into which instrumented classes should be placed. 45 | */ 46 | public File getInstrDirectory() { 47 | return instrDirectory; 48 | } 49 | 50 | /** 51 | * {@inheritDoc} 52 | */ 53 | @Override 54 | public String toString() { 55 | return "baseDir: " + baseDirectory.getPath() + 56 | ", instrDir: " + instrDirectory.getPath(); 57 | } 58 | } 59 | 60 | -------------------------------------------------------------------------------- /jdbl-core/src/main/java/se/kth/castor/jdbl/test/StackLine.java: -------------------------------------------------------------------------------- 1 | package se.kth.castor.jdbl.test; 2 | 3 | import java.util.Objects; 4 | 5 | public class StackLine 6 | { 7 | private String className; 8 | private String method; 9 | private String file; 10 | private int line; 11 | 12 | public StackLine(String className, String method, String file, int line) 13 | { 14 | this.className = className; 15 | this.method = method; 16 | this.file = file; 17 | this.line = line; 18 | } 19 | 20 | public String getClassName() 21 | { 22 | return className; 23 | } 24 | 25 | public String getMethod() 26 | { 27 | return method; 28 | } 29 | 30 | public String getFile() 31 | { 32 | return file; 33 | } 34 | 35 | public int getLine() 36 | { 37 | return line; 38 | } 39 | 40 | @Override 41 | public boolean equals(Object o) 42 | { 43 | if (this == o) { 44 | return true; 45 | } 46 | if (o == null || getClass() != o.getClass()) { 47 | return false; 48 | } 49 | StackLine stackLine = (StackLine) o; 50 | return line == stackLine.line && 51 | Objects.equals(className, stackLine.className) && 52 | Objects.equals(method, stackLine.method) && 53 | Objects.equals(file, stackLine.file); 54 | } 55 | 56 | @Override 57 | public int hashCode() 58 | { 59 | return Objects.hash(className, method, file, line); 60 | } 61 | 62 | @Override 63 | public String toString() 64 | { 65 | return "StackLine{" + 66 | "className='" + className + '\'' + 67 | ", method='" + method + '\'' + 68 | ", file='" + file + '\'' + 69 | ", line=" + line + 70 | '}'; 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /jdbl-maven-plugin/src/it/dummy-project/src/main/java/enums/CropState.java: -------------------------------------------------------------------------------- 1 | package enums; 2 | 3 | import java.util.HashMap; 4 | import java.util.Map; 5 | 6 | /** 7 | * Represents the different growth states of crops 8 | */ 9 | public enum CropState { 10 | 11 | /** 12 | * State when first seeded 13 | */ 14 | SEEDED(0x0), 15 | /** 16 | * First growth stage 17 | */ 18 | GERMINATED(0x1), 19 | /** 20 | * Second growth stage 21 | */ 22 | VERY_SMALL(0x2), 23 | /** 24 | * Third growth stage 25 | */ 26 | SMALL(0x3), 27 | /** 28 | * Fourth growth stage 29 | */ 30 | MEDIUM(0x4), 31 | /** 32 | * Fifth growth stage 33 | */ 34 | TALL(0x5), 35 | /** 36 | * Almost ripe stage 37 | */ 38 | VERY_TALL(0x6), 39 | /** 40 | * Ripe stage 41 | */ 42 | RIPE(0x7); 43 | 44 | private final byte data; 45 | private final static Map BY_DATA = new HashMap<>(); 46 | 47 | private CropState(final int data) { 48 | this.data = (byte) data; 49 | } 50 | 51 | /** 52 | * Gets the associated data value representing this growth state 53 | * 54 | * @return A byte containing the data value of this growth state 55 | */ 56 | public byte getData() { 57 | return data; 58 | } 59 | 60 | /** 61 | * Gets the CropState with the given data value 62 | * 63 | * @param data 64 | * Data value to fetch 65 | * @return The {@link CropState} representing the given value, or null if 66 | * it doesn't exist 67 | */ 68 | public static CropState getByData(final byte data) { 69 | return BY_DATA.get(data); 70 | } 71 | 72 | static { 73 | for (CropState cropState : values()) { 74 | BY_DATA.put(cropState.getData(), cropState); 75 | } 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /jdbl-core/src/test/java/se/kth/castor/jdbl/util/MyFileUtilsTest.java: -------------------------------------------------------------------------------- 1 | package se.kth.castor.jdbl.util; 2 | 3 | import java.io.File; 4 | import java.io.IOException; 5 | import java.util.Arrays; 6 | import java.util.HashSet; 7 | import java.util.Set; 8 | 9 | import org.junit.After; 10 | import org.junit.Before; 11 | import org.junit.Test; 12 | 13 | import static org.junit.jupiter.api.Assertions.assertEquals; 14 | import static org.junit.jupiter.api.Assertions.assertTrue; 15 | import se.kth.castor.jdbl.util.MyFileUtils; 16 | 17 | public class MyFileUtilsTest 18 | { 19 | Set exclusionSet; 20 | Set classesUsed; 21 | String projectBaseDir; 22 | File inputDir; 23 | File outputDir; 24 | 25 | @Before 26 | public void setupFiles() 27 | { 28 | exclusionSet = new HashSet<>(); 29 | classesUsed = new HashSet<>(Arrays.asList("calc.MainCalculator", "calc.Calculator")); 30 | projectBaseDir = "src/test/resources/classes/output/"; 31 | inputDir = new File("src/test/resources/classes"); 32 | outputDir = new File("src/test/resources/classes/output"); 33 | } 34 | 35 | @Test 36 | public void deleteUnusedClasses() throws IOException 37 | { 38 | org.apache.commons.io.FileUtils.copyDirectory(inputDir, outputDir); 39 | MyFileUtils myFileUtils = new MyFileUtils(outputDir.getAbsolutePath(), exclusionSet, classesUsed, projectBaseDir, null); 40 | myFileUtils.deleteUnusedClasses(outputDir.getAbsolutePath()); 41 | File reportFile = new File(projectBaseDir + ".jdbl/debloat-report.csv"); 42 | assertTrue(reportFile.exists()); 43 | assertEquals(2, new File(outputDir.getAbsolutePath() + "/calc").listFiles().length); 44 | } 45 | 46 | @After 47 | public void restoreFiles() throws IOException 48 | { 49 | org.apache.commons.io.FileUtils.deleteDirectory(outputDir); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /jdbl-maven-plugin/src/it/dummy-project/src/main/java/lambda/OrderMatcherWithFees.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2015 Gareth Jon Lynch 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy of 7 | * this software and associated documentation files (the "Software"), to deal in 8 | * the Software without restriction, including without limitation the rights to 9 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 10 | * the Software, and to permit persons to whom the Software is furnished to do so, 11 | * subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 18 | * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 19 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 20 | * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 21 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | */ 23 | 24 | package lambda; 25 | 26 | import java.math.BigDecimal; 27 | 28 | import common.Order; 29 | 30 | /** 31 | * Interface for providing query implementations for matching orders factoring in fees. 32 | * 33 | * @author gazbert 34 | */ 35 | public interface OrderMatcherWithFees 36 | { 37 | /** 38 | * Executes a query to see if an order matches. Fees are factored in. 39 | * 40 | * @param order the order to query. 41 | * @param fee the exchange fee. 42 | * @return true if order matched query, false otherwise. 43 | */ 44 | boolean executeQuery(Order order, BigDecimal fee); 45 | } 46 | -------------------------------------------------------------------------------- /jdbl-core/src/main/java/se/kth/castor/jdbl/debloat/AbstractMethodDebloat.java: -------------------------------------------------------------------------------- 1 | package se.kth.castor.jdbl.debloat; 2 | 3 | import java.io.IOException; 4 | import java.util.Map; 5 | import java.util.Set; 6 | 7 | import se.kth.castor.jdbl.coverage.UsageAnalysis; 8 | import se.kth.castor.jdbl.util.MyFileWriter; 9 | 10 | public abstract class AbstractMethodDebloat 11 | { 12 | protected UsageAnalysis usageAnalysis; 13 | protected String outputDirectory; 14 | protected String projectBaseDir; 15 | protected int nbMethodsRemoved; 16 | protected MyFileWriter myFileWriter; 17 | 18 | public AbstractMethodDebloat(String outputDirectory, UsageAnalysis usageAnalysis, String projectBaseDir) 19 | { 20 | this.outputDirectory = outputDirectory; 21 | this.usageAnalysis = usageAnalysis; 22 | this.projectBaseDir = projectBaseDir; 23 | this.nbMethodsRemoved = 0; 24 | this.myFileWriter = new MyFileWriter(projectBaseDir); 25 | } 26 | 27 | /** 28 | * Replace the body of bloated methods with UnsupportedOperationException in the class. 29 | * 30 | * @param clazz The fully qualified name of the used class. 31 | * @param usedMethods The name of the used methods in this class. 32 | */ 33 | public abstract void removeMethod(String clazz, Set usedMethods) throws IOException; 34 | 35 | /** 36 | * Iterate through the used classes to replace the body of bloated methods with 37 | * an UnsupportedOperationException. 38 | */ 39 | public void removeUnusedMethods() throws IOException 40 | { 41 | for (Map.Entry> entry : this.usageAnalysis.getAnalysis().entrySet()) { 42 | if (entry.getValue() != null) { 43 | this.removeMethod(entry.getKey().replace(".", "/"), entry.getValue()); 44 | } 45 | } 46 | } 47 | 48 | public int nbMethodsRemoved() 49 | { 50 | return nbMethodsRemoved; 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /jdbl-core/src/main/java/se/kth/castor/jdbl/deptree/AbstractLineBasedParser.java: -------------------------------------------------------------------------------- 1 | package se.kth.castor.jdbl.deptree; 2 | 3 | import java.io.BufferedReader; 4 | import java.io.IOException; 5 | import java.io.Reader; 6 | import java.util.ArrayList; 7 | import java.util.List; 8 | 9 | import org.apache.commons.lang3.StringUtils; 10 | 11 | public abstract class AbstractLineBasedParser extends AbstractParser 12 | { 13 | public static final String ARTIFACT = "artifact = "; 14 | protected int lineIndex = 0; 15 | 16 | protected List lines; 17 | 18 | protected List splitLines(final Reader reader) throws IOException 19 | { 20 | String line = null; 21 | final BufferedReader br; 22 | if (reader instanceof BufferedReader) { 23 | br = (BufferedReader) reader; 24 | } else { 25 | br = new BufferedReader(reader); 26 | } 27 | lines = new ArrayList<>(); 28 | while ((line = br.readLine()) != null) { 29 | lines.add(line); 30 | } 31 | return lines; 32 | } 33 | 34 | protected String extractActiveProjectArtifact() 35 | { 36 | String artifact = null; 37 | //start at next line and consume all lines containing "artifact =" or "project: "; record the last line containing "artifact =". 38 | boolean artifactFound = false; 39 | while (this.lineIndex < this.lines.size() - 1) { 40 | String tempLine = this.lines.get(this.lineIndex + 1); 41 | boolean artifactLine = !artifactFound && tempLine.contains(ARTIFACT); 42 | boolean projectLine = artifactFound && tempLine.contains("project: "); 43 | if (artifactLine || projectLine) { 44 | if (tempLine.contains(ARTIFACT) && !tempLine.contains("active project artifact:")) { 45 | artifact = StringUtils.substringBefore(StringUtils.substringAfter(tempLine, ARTIFACT), ";"); 46 | artifactFound = true; 47 | } 48 | this.lineIndex++; 49 | } else { 50 | break; 51 | } 52 | } 53 | return artifact; 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /jdbl-agent/src/main/java/se/kth/castor/jdbl/agent/Agent.java: -------------------------------------------------------------------------------- 1 | package se.kth.castor.jdbl.agent; 2 | 3 | import net.bytebuddy.agent.builder.AgentBuilder; 4 | import net.bytebuddy.matcher.ElementMatchers; 5 | 6 | import java.io.File; 7 | import java.io.FileWriter; 8 | import java.io.IOException; 9 | import java.lang.instrument.Instrumentation; 10 | import java.util.ArrayList; 11 | import java.util.HashSet; 12 | import java.util.Set; 13 | 14 | public class Agent { 15 | protected static final Set calledMethods = new HashSet<>(); 16 | 17 | public static void premain(String agentArgs, Instrumentation inst) { 18 | Runtime.getRuntime().addShutdownHook(new Thread(() -> { 19 | ArrayList list = new ArrayList<>(calledMethods); 20 | list.sort(null); 21 | try (FileWriter heapFileWritter = new FileWriter(new File("agentCoverage.csv"), true)) { 22 | for (String calledMethod : list) { 23 | heapFileWritter.append(calledMethod).append("\n").flush(); 24 | } 25 | } catch (IOException e) { 26 | e.printStackTrace(); 27 | } 28 | })); 29 | AgentBuilder.Transformer.ForAdvice advice = new AgentBuilder.Transformer.ForAdvice() 30 | .include(inst.getClass().getClassLoader()) 31 | .advice(ElementMatchers.any(), CallAdvice.class.getCanonicalName()); 32 | 33 | new AgentBuilder.Default() 34 | .ignore(ElementMatchers.nameStartsWith("net.bytebuddy.") 35 | .or(ElementMatchers.nameStartsWith("se.kth.castor.jdbl.")) 36 | .or(ElementMatchers.nameStartsWith("org.jacoco.")) 37 | .or(ElementMatchers.nameStartsWith("org.apache.maven.")) 38 | .or(ElementMatchers.nameStartsWith("org.objectweb.asm.")) 39 | .or(ElementMatchers.nameStartsWith("java.")) 40 | .or(ElementMatchers.nameStartsWith("jdk.")) 41 | .or(ElementMatchers.nameStartsWith("sun.")) 42 | .or(ElementMatchers.nameStartsWith("com.sun."))) 43 | .type(ElementMatchers.any()).transform(advice).installOn(inst); 44 | } 45 | 46 | } 47 | -------------------------------------------------------------------------------- /jdbl-maven-plugin/src/it/dummy-project/src/main/java/defaultmethods/MyTradingApi.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2015 Gareth Jon Lynch 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy of 7 | * this software and associated documentation files (the "Software"), to deal in 8 | * the Software without restriction, including without limitation the rights to 9 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 10 | * the Software, and to permit persons to whom the Software is furnished to do so, 11 | * subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 18 | * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 19 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 20 | * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 21 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | */ 23 | 24 | package defaultmethods; 25 | 26 | 27 | import java.util.ArrayList; 28 | import java.util.List; 29 | import java.util.UUID; 30 | 31 | import common.Order; 32 | 33 | /** 34 | * An implementation of the Trading API. 35 | *

36 | * Note: the TradingApi#getImplName has not been implemented yet. 37 | * 38 | * @author gazbert 39 | */ 40 | public class MyTradingApi implements TradingApi { 41 | 42 | @Override 43 | public boolean addOrder(Order order) { 44 | System.out.println(MyTradingApi.class.getSimpleName() + " addOrder called"); 45 | return false; 46 | } 47 | 48 | @Override 49 | public boolean cancelOrder(UUID orderId) { 50 | System.out.println(MyTradingApi.class.getSimpleName() + " cancelOrder called"); 51 | return false; 52 | } 53 | 54 | @Override 55 | public List getOpenOrders(int marketId) { 56 | System.out.println(MyTradingApi.class.getSimpleName() + " getOpenOrders called"); 57 | return new ArrayList<>(); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /jdbl-core/src/main/java/se/kth/castor/jdbl/adapter/ClassAdapter.java: -------------------------------------------------------------------------------- 1 | package se.kth.castor.jdbl.adapter; 2 | 3 | import java.io.File; 4 | import java.io.FileInputStream; 5 | import java.io.IOException; 6 | 7 | import org.objectweb.asm.ClassReader; 8 | import org.objectweb.asm.ClassVisitor; 9 | import org.objectweb.asm.Opcodes; 10 | 11 | public class ClassAdapter extends ClassVisitor implements Opcodes 12 | { 13 | private boolean isRemovable = false; 14 | 15 | private String baseDir; 16 | 17 | public ClassAdapter(final ClassVisitor cv, String baseDir) 18 | { 19 | super(Opcodes.ASM8, cv); 20 | this.baseDir = baseDir; 21 | } 22 | 23 | @Override 24 | public void visit( 25 | final int version, 26 | final int access, 27 | final String name, 28 | final String signature, 29 | final String superName, 30 | final String[] interfaces) 31 | { 32 | super.visit(version, access, name, signature, superName, interfaces); 33 | 34 | isRemovable = !(((access & Opcodes.ACC_INTERFACE) != 0) || 35 | ((access & Opcodes.ACC_ENUM) != 0) || 36 | ((access & Opcodes.ACC_ANNOTATION) != 0) || 37 | ((access & Opcodes.ACC_FINAL) != 0) || 38 | // (name.matches(".*[$]\\d+")) || // annonymous classes 39 | (name.contains("$")) || 40 | extendsThrowable(superName)); 41 | } 42 | 43 | private boolean extendsThrowable(String className) 44 | { 45 | ClassReader cr = null; 46 | try { 47 | if (className.startsWith("java/") || className.startsWith("sun/")) { 48 | 49 | if (className.endsWith("Exception") || className.endsWith("Error")) { 50 | return true; 51 | } 52 | return false; 53 | } else { 54 | cr = new ClassReader(new FileInputStream(new File(baseDir + "/" + className + ".class"))); 55 | } 56 | } catch (IOException e) { 57 | return true; 58 | } 59 | String superName = cr.getSuperName(); 60 | if (superName != null && !superName.equals("java/lang/Object")) { 61 | String superClass = superName.replace('.', '/'); 62 | return extendsThrowable(superClass); 63 | } 64 | return false; 65 | } 66 | } 67 | 68 | -------------------------------------------------------------------------------- /jdbl-core/src/main/java/se/kth/castor/jdbl/util/CmdExec.java: -------------------------------------------------------------------------------- 1 | package se.kth.castor.jdbl.util; 2 | 3 | import java.io.BufferedReader; 4 | import java.io.InputStreamReader; 5 | import java.util.HashSet; 6 | import java.util.Set; 7 | 8 | import org.apache.commons.lang3.ArrayUtils; 9 | import org.apache.log4j.LogManager; 10 | import org.apache.log4j.Logger; 11 | 12 | public class CmdExec 13 | { 14 | private static final Logger LOGGER = LogManager.getLogger(CmdExec.class.getName()); 15 | 16 | /** 17 | * Creates a system process to execute a Java class with its parameters via command line. 18 | * E.g, java -verbose:class -jar target/clitools-1.0.0-SNAPSHOT-jar-with-dependencies.jar whoami | grep "\[Loaded " | 19 | * grep -v " from /usr/lib" | cut -d ' ' -f2 | sort > loaded-classes 20 | * 21 | * @param classPath Path to the .class file 22 | * @param clazzFullyQualifiedName Fully qualified name of the class to execute 23 | * @param parameters The parameters (i.e, -verbose:class) 24 | * @return The set of classes in the classpath that were loaded during the execution of the class 25 | */ 26 | public Set execProcess(String classPath, String clazzFullyQualifiedName, String[] parameters) 27 | { 28 | Set result = new HashSet<>(); 29 | try { 30 | String line; 31 | String[] cmd = {"java", 32 | "-verbose:class", 33 | "-classpath", 34 | classPath, 35 | clazzFullyQualifiedName}; 36 | cmd = ArrayUtils.addAll(cmd, parameters); 37 | for (String s : cmd) { 38 | System.out.print(s + " "); 39 | } 40 | System.out.println(); 41 | Process p = Runtime.getRuntime().exec(cmd); 42 | BufferedReader input = new BufferedReader(new InputStreamReader(p.getInputStream())); 43 | while ((line = input.readLine()) != null) { 44 | System.out.println(line); 45 | if (line.startsWith("[Loaded ") && line.endsWith("target/classes" + "/]")) { 46 | result.add(line.split(" ")[1]); 47 | } 48 | } 49 | input.close(); 50 | } catch (Exception e) { 51 | LOGGER.error("Failed to run: " + e); 52 | } 53 | return result; 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /jdbl-core/src/test/resources/calc/inst/report/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Coverage report 5 | 6 | 51 | 52 | 53 |

54 |
55 |
56 | 57 |
58 |
59 | 60 |
61 |
62 |
63 | 64 |
65 |
66 | 67 | 68 | -------------------------------------------------------------------------------- /jdbl-core/src/main/java/se/kth/castor/jdbl/deptree/AbstractTextVisitor.java: -------------------------------------------------------------------------------- 1 | package se.kth.castor.jdbl.deptree; 2 | 3 | import java.io.BufferedWriter; 4 | import java.io.IOException; 5 | 6 | import org.apache.commons.io.output.StringBuilderWriter; 7 | import org.apache.log4j.LogManager; 8 | import org.apache.log4j.Logger; 9 | 10 | public abstract class AbstractTextVisitor implements Visitor 11 | { 12 | private static final Logger LOGGER = LogManager.getLogger(AbstractTextVisitor.class.getName()); 13 | 14 | private final StringBuilderWriter sbw; 15 | private final BufferedWriter bw; 16 | 17 | public AbstractTextVisitor() 18 | { 19 | sbw = new StringBuilderWriter(); 20 | bw = new BufferedWriter(sbw); 21 | } 22 | 23 | public void visit(Node node) 24 | { 25 | try { 26 | writeNode(node); 27 | for (Node child : node.getChildNodes()) { 28 | visit(child); 29 | } 30 | } catch (IOException ignored) { 31 | LOGGER.error("Error visiting node: " + node.getArtifactCanonicalForm()); 32 | } 33 | } 34 | 35 | private void writeNode(Node node) throws IOException 36 | { 37 | //the tree symbols 38 | writeTreeSymbols(node); 39 | //the node itself 40 | bw.write(node.getArtifactCanonicalForm()); 41 | bw.newLine(); 42 | } 43 | 44 | private void writeTreeSymbols(Node node) throws IOException 45 | { 46 | if (node.getParent() != null) { 47 | writeParentTreeSymbols(node.getParent()); 48 | bw.write(getTreeSymbols(node)); 49 | } 50 | } 51 | 52 | private void writeParentTreeSymbols(Node node) throws IOException 53 | { 54 | if (node.getParent() != null) { 55 | writeParentTreeSymbols(node.getParent()); 56 | bw.write(getParentTreeSymbols(node)); 57 | } 58 | } 59 | 60 | public abstract String getTreeSymbols(Node node); 61 | 62 | public abstract String getParentTreeSymbols(Node node); 63 | 64 | @Override 65 | public String toString() 66 | { 67 | try { 68 | bw.flush(); 69 | sbw.flush(); 70 | return sbw.toString(); 71 | } catch (IOException e) { 72 | return ""; 73 | } finally { 74 | try { 75 | bw.close(); 76 | } catch (IOException ignored) { 77 | LOGGER.error("Error while parsing to string."); 78 | } 79 | sbw.close(); 80 | } 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /jdbl-core/src/main/java/se/kth/castor/jdbl/coverage/UsageAnalysis.java: -------------------------------------------------------------------------------- 1 | package se.kth.castor.jdbl.coverage; 2 | 3 | import java.util.HashMap; 4 | import java.util.Map; 5 | import java.util.Set; 6 | 7 | public class UsageAnalysis 8 | { 9 | Map> analysis; 10 | 11 | public UsageAnalysis() 12 | { 13 | this.analysis = new HashMap<>(); 14 | } 15 | 16 | public void setAnalysis(final Map> analysis) 17 | { 18 | this.analysis = analysis; 19 | } 20 | 21 | public Set methods(String clazz) 22 | { 23 | return analysis.get(clazz); 24 | } 25 | 26 | public void addEntry(String clazz, Set methods) 27 | { 28 | analysis.put(clazz, methods); 29 | } 30 | 31 | public Map> getAnalysis() 32 | { 33 | return analysis; 34 | } 35 | 36 | public boolean containsClazz(String clazz) 37 | { 38 | return analysis.containsKey(clazz); 39 | } 40 | 41 | public void removeUncoveredClasses() 42 | { 43 | analysis.entrySet().removeIf(entry -> entry.getValue().isEmpty()); 44 | } 45 | 46 | public Set classes() 47 | { 48 | return analysis.keySet(); 49 | } 50 | 51 | /** 52 | * Computes the union between the current usage analysis and another usage analysis. 53 | */ 54 | public UsageAnalysis mergeWith(UsageAnalysis usageAnalysis) 55 | { 56 | UsageAnalysis mergedUsageAnalysis = new UsageAnalysis(); 57 | mergeClasses(usageAnalysis); 58 | mergeMethods(usageAnalysis, mergedUsageAnalysis); 59 | return mergedUsageAnalysis; 60 | } 61 | 62 | private void mergeMethods(UsageAnalysis usageAnalysis, UsageAnalysis mergedUsageAnalysis) 63 | { 64 | for (String clazz : classes()) { 65 | Set methods = methods(clazz); 66 | if (usageAnalysis.containsClazz(clazz)) { 67 | methods.addAll(usageAnalysis.methods(clazz)); 68 | } 69 | mergedUsageAnalysis.addEntry(clazz, methods); 70 | } 71 | } 72 | 73 | private void mergeClasses(UsageAnalysis usageAnalysis) 74 | { 75 | for (String clazz : usageAnalysis.classes()) { 76 | if (!containsClazz(clazz)) { 77 | addEntry(clazz, usageAnalysis.methods(clazz)); 78 | } 79 | } 80 | } 81 | 82 | @Override 83 | public String toString() 84 | { 85 | StringBuilder sb = new StringBuilder(); 86 | analysis.forEach((key, value) -> sb.append(key + " : " + value + "\n")); 87 | return sb.toString(); 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /jdbl-maven-plugin/src/it/dummy-project/src/main/java/annotations/ObjectToJsonConverter.java: -------------------------------------------------------------------------------- 1 | package annotations; 2 | 3 | import java.lang.reflect.Field; 4 | import java.lang.reflect.InvocationTargetException; 5 | import java.lang.reflect.Method; 6 | import java.util.HashMap; 7 | import java.util.Map; 8 | import java.util.Objects; 9 | import java.util.stream.Collectors; 10 | 11 | public class ObjectToJsonConverter 12 | { 13 | public String convertToJson(Object object) throws JsonSerializationException 14 | { 15 | try { 16 | 17 | checkIfSerializable(object); 18 | initializeObject(object); 19 | return getJsonString(object); 20 | 21 | } catch (Exception e) { 22 | throw new JsonSerializationException(e.getMessage()); 23 | } 24 | } 25 | 26 | private void checkIfSerializable(Object object) 27 | { 28 | if (Objects.isNull(object)) { 29 | throw new JsonSerializationException("Can't serialize a null object"); 30 | } 31 | 32 | Class clazz = object.getClass(); 33 | if (!clazz.isAnnotationPresent(JsonSerializable.class)) { 34 | throw new JsonSerializationException("The class " + clazz.getSimpleName() + " is not annotated with JsonSerializable"); 35 | } 36 | } 37 | 38 | private void initializeObject(Object object) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException 39 | { 40 | Class clazz = object.getClass(); 41 | for (Method method : clazz.getDeclaredMethods()) { 42 | if (method.isAnnotationPresent(Init.class)) { 43 | method.setAccessible(true); 44 | method.invoke(object); 45 | } 46 | } 47 | } 48 | 49 | private String getJsonString(Object object) throws IllegalArgumentException, IllegalAccessException 50 | { 51 | Class clazz = object.getClass(); 52 | Map jsonElementsMap = new HashMap<>(); 53 | for (Field field : clazz.getDeclaredFields()) { 54 | field.setAccessible(true); 55 | if (field.isAnnotationPresent(JsonElement.class)) { 56 | jsonElementsMap.put(getKey(field), (String) field.get(object)); 57 | } 58 | } 59 | 60 | String jsonString = jsonElementsMap.entrySet() 61 | .stream() 62 | .map(entry -> "\"" + entry.getKey() + "\":\"" + entry.getValue() + "\"") 63 | .collect(Collectors.joining(",")); 64 | return "{" + jsonString + "}"; 65 | } 66 | 67 | private String getKey(Field field) 68 | { 69 | String value = field.getAnnotation(JsonElement.class) 70 | .key(); 71 | return value.isEmpty() ? field.getName() : value; 72 | } 73 | } 74 | 75 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: build 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | pull_request: 8 | branches: 9 | - master 10 | 11 | jobs: 12 | build: 13 | strategy: 14 | max-parallel: 1 15 | matrix: 16 | os: [ ubuntu-latest ] 17 | java: [ 11 ] 18 | runs-on: ${{ matrix.os }} 19 | name: Build with Java ${{ matrix.java }} on ${{ matrix.os }} 20 | steps: 21 | - name: "Checkout" 22 | uses: actions/checkout@v2 23 | with: 24 | fetch-depth: 0 25 | - name: Java ${{ matrix.java }} 26 | uses: actions/setup-java@v1 27 | with: 28 | java-version: ${{ matrix.java }} 29 | - name: "Cache Local Maven Repository" 30 | uses: actions/cache@v1 31 | with: 32 | path: ~/.m2 33 | key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }} 34 | restore-keys: ${{ runner.os }}-m2 35 | # - name: "CheckStyle" 36 | # run: mvn validate --errors 37 | - name: "Compile and Install" 38 | run: mvn clean install -DskipTests --errors 39 | - name: "Unit Tests" 40 | run: mvn test --errors --fail-at-end 41 | # - name: "Integration Tests" 42 | # run: mvn failsafe:integration-test --errors --fail-at-end 43 | # The following is only executed on Ubuntu on Java 11 44 | - name: "JaCoCo Coverage Report" 45 | if: matrix.os == 'ubuntu-latest' && matrix.java == 11 && github.repository == 'castor-software/jdbl' 46 | run: mvn jacoco:report 47 | - name: "Codecov" 48 | if: matrix.os == 'ubuntu-latest' && matrix.java == 11 && github.repository == 'castor-software/jdbl' 49 | uses: codecov/codecov-action@v1 50 | with: 51 | token: ${{ secrets.CODECOV_TOKEN }} 52 | files: ./jdbl-core/target/site/jacoco/jacoco.xml 53 | flags: unittests 54 | - name: "Cache SonarCloud" 55 | if: matrix.os == 'ubuntu-latest' && matrix.java == 11 && github.repository == 'castor-software/jdbl' 56 | uses: actions/cache@v1 57 | with: 58 | path: ~/.sonar/cache 59 | key: ${{ runner.os }}-sonar 60 | restore-keys: ${{ runner.os }}-sonar 61 | - name: "SonarCloud" 62 | if: matrix.os == 'ubuntu-latest' && matrix.java == 11 && github.repository == 'castor-software/jdbl' 63 | run: mvn sonar:sonar -Dsonar.projectKey=castor-software_jdbl -Dsonar.organization=castor-software -Dsonar.host.url=https://sonarcloud.io -Dsonar.login=${{ secrets.SONAR_TOKEN }} -Dsonar.java.source=11 -Dsonar.java.target=11 64 | env: 65 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 66 | SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} -------------------------------------------------------------------------------- /jdbl-maven-plugin/src/it/dummy-project/src/test/java/interfaces/ApplicationTest.java: -------------------------------------------------------------------------------- 1 | package interfaces; 2 | 3 | import org.junit.BeforeClass; 4 | import org.junit.Test; 5 | import static org.assertj.core.api.Assertions.*; 6 | 7 | public class ApplicationTest { 8 | 9 | private static Car car; 10 | private static Motorbike motorbike; 11 | 12 | @BeforeClass 13 | public static void setUpCarInstance() { 14 | car = new Car("BMW"); 15 | } 16 | 17 | @BeforeClass 18 | public static void setUpMotorbikeInstance() { 19 | motorbike = new Motorbike("Yamaha"); 20 | } 21 | 22 | @Test 23 | public void givenCarInstace_whenBrandisBMW_thenOneAssertion() { 24 | assertThat(car.getBrand()).isEqualTo("BMW"); 25 | } 26 | 27 | @Test 28 | public void givenCarInstance_whenCallingSpeedUp_thenOneAssertion() { 29 | assertThat(car.speedUp()).isEqualTo("The car is speeding up."); 30 | } 31 | 32 | @Test 33 | public void givenCarInstance_whenCallingSlowDown_thenOneAssertion() { 34 | assertThat(car.slowDown()).isEqualTo("The car is slowing down."); 35 | } 36 | 37 | @Test 38 | public void givenCarInstance_whenCallingTurnAlarmOn_thenOneAssertion() { 39 | assertThat(car.turnAlarmOn()).isEqualTo("Turning the vehice alarm on."); 40 | } 41 | 42 | @Test 43 | public void givenCarInstance_whenCallingTurnAlarmOff_thenOneAssertion() { 44 | assertThat(car.turnAlarmOff()).isEqualTo("Turning the vehicle alarm off."); 45 | } 46 | 47 | @Test 48 | public void givenVehicleInterface_whenCallinggetHorsePower_thenOneAssertion() { 49 | assertThat(Vehicle.getHorsePower(2500, 480)).isEqualTo(228); 50 | } 51 | 52 | @Test 53 | public void givenMooorbikeInstace_whenBrandisYamaha_thenOneAssertion() { 54 | assertThat(motorbike.getBrand()).isEqualTo("Yamaha"); 55 | } 56 | 57 | @Test 58 | public void givenMotorbikeInstance_whenCallingSpeedUp_thenOneAssertion() { 59 | assertThat(motorbike.speedUp()).isEqualTo("The motorbike is speeding up."); 60 | } 61 | 62 | @Test 63 | public void givenMotorbikeInstance_whenCallingSlowDown_thenOneAssertion() { 64 | assertThat(motorbike.slowDown()).isEqualTo("The motorbike is slowing down."); 65 | } 66 | 67 | @Test 68 | public void givenMotorbikeInstance_whenCallingTurnAlarmOn_thenOneAssertion() { 69 | assertThat(motorbike.turnAlarmOn()).isEqualTo("Turning the vehice alarm on."); 70 | } 71 | 72 | @Test 73 | public void givenMotorbikeInstance_whenCallingTurnAlarmOff_thenOneAssertion() { 74 | assertThat(motorbike.turnAlarmOff()).isEqualTo("Turning the vehicle alarm off."); 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /jdbl-core/src/main/java/se/kth/castor/jdbl/deptree/TextParser.java: -------------------------------------------------------------------------------- 1 | package se.kth.castor.jdbl.deptree; 2 | 3 | import java.io.IOException; 4 | import java.io.Reader; 5 | 6 | public class TextParser extends AbstractLineBasedParser 7 | { 8 | public Node parse(Reader reader) throws ParseException 9 | { 10 | try { 11 | this.lines = splitLines(reader); 12 | } catch (IOException e) { 13 | throw new ParseException(e); 14 | } 15 | 16 | if (lines.isEmpty()) { 17 | return null; 18 | } 19 | return parseInternal(0); 20 | } 21 | 22 | private Node parseInternal(final int depth) 23 | { 24 | //current node 25 | final Node node = this.parseLine(); 26 | this.lineIndex++; 27 | 28 | //children 29 | while (this.lineIndex < this.lines.size() && this.computeDepth(this.lines.get(this.lineIndex)) > depth) { 30 | final Node child = this.parseInternal(depth + 1); 31 | if (node != null) { 32 | node.addChildNode(child); 33 | } 34 | } 35 | return node; 36 | 37 | } 38 | 39 | private int computeDepth(final String line) 40 | { 41 | return getArtifactIndex(line) / 3; 42 | } 43 | 44 | /** 45 | * sample lineIndex structure: 46 | *
|  |  \- org.apache.activemq:activeio-core:test-jar:tests:3.1.0:compile
47 | * 48 | * @return 49 | */ 50 | private Node parseLine() 51 | { 52 | String line = this.lines.get(this.lineIndex); 53 | String artifact; 54 | if (line.contains("active project artifact:")) { 55 | artifact = extractActiveProjectArtifact(); 56 | } else { 57 | artifact = extractArtifact(line); 58 | } 59 | return parseArtifactString(artifact); 60 | } 61 | 62 | private String extractArtifact(String line) 63 | { 64 | return line.substring(getArtifactIndex(line)); 65 | } 66 | 67 | private int getArtifactIndex(final String line) 68 | { 69 | for (int i = 0; i < line.length(); i++) { 70 | final char c = line.charAt(i); 71 | switch (c) { 72 | case ' '://whitespace, standard and extended 73 | case '|'://standard 74 | case '+'://standard 75 | case '\\'://standard 76 | case '-'://standard 77 | case '³'://extended 78 | case 'Ã'://extended 79 | case 'Ä'://extended 80 | case 'À'://extended 81 | continue; 82 | default: 83 | return i; 84 | } 85 | } 86 | return -1; 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /jdbl-maven-plugin/src/main/java/se/kth/castor/jdbl/plugin/AbstractDebloatMojo.java: -------------------------------------------------------------------------------- 1 | package se.kth.castor.jdbl.plugin; 2 | 3 | import java.io.BufferedReader; 4 | import java.io.File; 5 | import java.io.IOException; 6 | import java.io.InputStreamReader; 7 | 8 | import org.apache.maven.plugin.AbstractMojo; 9 | import org.apache.maven.plugin.MojoExecutionException; 10 | import org.apache.maven.plugin.MojoFailureException; 11 | import org.apache.maven.plugins.annotations.Parameter; 12 | import org.apache.maven.project.MavenProject; 13 | 14 | public abstract class AbstractDebloatMojo extends AbstractMojo 15 | { 16 | /** 17 | * The maven home file, assuming either an environment variable M2_HOME, or that mvn command exists in PATH. 18 | */ 19 | public static File mavenHome; 20 | static { 21 | if (System.getenv().containsKey("M2_HOME")) { 22 | mavenHome = new File(System.getenv().get("M2_HOME")); 23 | } else { 24 | try { 25 | Process exec = Runtime.getRuntime().exec("mvn --version"); 26 | BufferedReader stdInput = new BufferedReader(new InputStreamReader(exec.getInputStream())); 27 | exec.waitFor(); 28 | mavenHome = new File(stdInput.readLine().replace("Maven home: ", "")); 29 | } catch (Exception e) { 30 | e.printStackTrace(); 31 | mavenHome = new File(""); 32 | } 33 | } 34 | } 35 | 36 | private static final String LINE_SEPARATOR = "------------------------------------------------------------------------"; 37 | 38 | 39 | @Parameter(defaultValue = "${project}", readonly = true) 40 | private MavenProject project; 41 | 42 | /** 43 | * Skip plugin execution completely. 44 | */ 45 | @Parameter(property = "skipJDBL", defaultValue = "false") 46 | private boolean skipJDBL; 47 | 48 | @Override 49 | public final void execute() 50 | throws MojoExecutionException, MojoFailureException 51 | { 52 | if (isSkipJDBL()) { 53 | getLog().info("Skipping plugin execution..."); 54 | return; 55 | } 56 | this.doExecute(); 57 | } 58 | 59 | protected abstract void doExecute() 60 | throws MojoExecutionException, MojoFailureException; 61 | 62 | public boolean isSkipJDBL() 63 | { 64 | return this.skipJDBL; 65 | } 66 | 67 | public MavenProject getProject() 68 | { 69 | return project; 70 | } 71 | 72 | public static File getMavenHome() 73 | { 74 | return mavenHome; 75 | } 76 | 77 | public void printCustomStringToConsole(final String s) 78 | { 79 | this.getLog().info(LINE_SEPARATOR); 80 | this.getLog().info(s); 81 | this.getLog().info(LINE_SEPARATOR); 82 | } 83 | 84 | public static String getLineSeparator() 85 | { 86 | return LINE_SEPARATOR; 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /jdbl-app/src/main/java/se/kth/castor/jdbl/DebloatBuilder.java: -------------------------------------------------------------------------------- 1 | package se.kth.castor.jdbl; 2 | 3 | import java.io.File; 4 | import java.util.List; 5 | 6 | public class DebloatBuilder { 7 | 8 | //--------------------------------/ 9 | //-------- CLASS FIELD/S --------/ 10 | //------------------------------/ 11 | 12 | private File inputFilePath; 13 | private File outputFilePath; 14 | private String entryClass; 15 | private String entryMethod; 16 | private List entryParams; 17 | 18 | //--------------------------------/ 19 | //------- PUBLIC METHOD/S -------/ 20 | //------------------------------/ 21 | 22 | public DebloatBuilder addInputFilePath(File inputFilePath) { 23 | this.inputFilePath = inputFilePath; 24 | return this; 25 | } 26 | 27 | public DebloatBuilder addOutputFilePath(File outputFilePath) { 28 | this.outputFilePath = outputFilePath; 29 | return this; 30 | } 31 | 32 | public DebloatBuilder addEntryClass(String entryClass) { 33 | this.entryClass = entryClass; 34 | return this; 35 | } 36 | 37 | public DebloatBuilder addEntryMethod(String entryMethod) { 38 | this.entryMethod = entryMethod; 39 | return this; 40 | } 41 | 42 | public DebloatBuilder addEntryParam(List entryParams) { 43 | this.entryParams = entryParams; 44 | return this; 45 | } 46 | 47 | /** 48 | * Return the finally constructed DebloaterBuilder object. 49 | */ 50 | public DebloatBuilder build() { 51 | DebloatBuilder debloatBuilder = new DebloatBuilder(); 52 | debloatBuilder.inputFilePath = this.inputFilePath; 53 | debloatBuilder.outputFilePath = this.outputFilePath; 54 | debloatBuilder.entryClass = this.entryClass; 55 | debloatBuilder.entryMethod = this.entryMethod; 56 | debloatBuilder.entryParams = this.entryParams; 57 | return debloatBuilder; 58 | } 59 | 60 | //--------------------------------/ 61 | //------- GETTER METHOD/S -------/ 62 | //------------------------------/ 63 | 64 | public File getInputFilePath() { 65 | return inputFilePath; 66 | } 67 | 68 | public File getOutputFilePath() { 69 | return outputFilePath; 70 | } 71 | 72 | public String getEntryClass() { 73 | return entryClass; 74 | } 75 | 76 | public String getEntryMethod() { 77 | return entryMethod; 78 | } 79 | 80 | public List getEntryParams() { 81 | return entryParams; 82 | } 83 | 84 | @Override 85 | public String toString() { 86 | return "inputFilePath=" + inputFilePath + 87 | ", outputFilePath=" + outputFilePath + 88 | ", entryClass='" + entryClass + '\'' + 89 | ", entryMethod='" + entryMethod + '\'' + 90 | ", entryParams='" + entryParams; 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /jdbl-maven-plugin/src/it/dummy-project/src/test/java/defaultmethods/TestDefaultMethodUsage.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2015 Gareth Jon Lynch 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy of 7 | * this software and associated documentation files (the "Software"), to deal in 8 | * the Software without restriction, including without limitation the rights to 9 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 10 | * the Software, and to permit persons to whom the Software is furnished to do so, 11 | * subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 18 | * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 19 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 20 | * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 21 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | */ 23 | 24 | package defaultmethods; 25 | 26 | import static org.junit.Assert.assertEquals; 27 | 28 | import java.util.Date; 29 | import java.util.List; 30 | 31 | import org.junit.Test; 32 | 33 | import common.Order; 34 | 35 | /** 36 | * Test class for demonstrating use of default and static methods on interfaces in Java 8. 37 | *

38 | * 39 | * @author gazbert 40 | * 41 | */ 42 | public class TestDefaultMethodUsage 43 | { 44 | /** 45 | * Shows use of default method. 46 | *

47 | * When you extend an interface that contains a default method, you treat it just like a superclass method: 48 | *

    49 | *
  • Not mention the default method at all - lets your extended interface inherit the default method.
  • 50 | *
  • Redeclare the default method - makes it abstract.
  • 51 | *
  • Redefine the default method - which overrides it.
  • 52 | *
53 | */ 54 | @Test 55 | public void showDefaultMethodUsage() 56 | { 57 | final TradingApi api = new MyTradingApi(); 58 | final List openOrders = api.getOpenOrders(1); 59 | assertEquals(0, openOrders.size()); 60 | 61 | // now invoke the default method 62 | assertEquals("Default API Impl", api.getImplName()); 63 | } 64 | 65 | /** 66 | * Shows how to use static methods on Java 8 interfaces. 67 | *

68 | * Note the use of Date - another demo will cover the new Java 8 java.time API :-) 69 | */ 70 | @Test 71 | public void showStaticInterfaceMethodUsage() 72 | { 73 | final Date time = TradingApi.getCurrentExchangeTime(); 74 | System.out.println("Exchange clock time: " + time); 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /jdbl-core/src/main/java/se/kth/castor/jdbl/debloat/EntryPointMethodDebloat.java: -------------------------------------------------------------------------------- 1 | package se.kth.castor.jdbl.debloat; 2 | 3 | import java.io.File; 4 | import java.io.FileInputStream; 5 | import java.io.FileOutputStream; 6 | import java.io.IOException; 7 | import java.io.OutputStream; 8 | import java.util.Set; 9 | 10 | import org.apache.log4j.LogManager; 11 | import org.apache.log4j.Logger; 12 | import org.objectweb.asm.ClassReader; 13 | import org.objectweb.asm.ClassVisitor; 14 | import org.objectweb.asm.ClassWriter; 15 | import org.objectweb.asm.MethodVisitor; 16 | import org.objectweb.asm.Opcodes; 17 | 18 | import se.kth.castor.jdbl.coverage.UsageAnalysis; 19 | import se.kth.castor.jdbl.coverage.UsageStatusEnum; 20 | import se.kth.castor.jdbl.util.ClassFileType; 21 | 22 | public class EntryPointMethodDebloat extends AbstractMethodDebloat 23 | { 24 | protected static final Logger LOGGER = LogManager.getLogger(EntryPointMethodDebloat.class); 25 | 26 | public EntryPointMethodDebloat(String outputDirectory, UsageAnalysis usageAnalysis, String projectBaseDir) 27 | { 28 | super(outputDirectory, usageAnalysis, projectBaseDir); 29 | } 30 | 31 | @Override 32 | public void removeMethod(String clazz, Set usedMethods) throws IOException 33 | { 34 | FileInputStream in = new FileInputStream(new File(outputDirectory + "/" + clazz + ".class")); 35 | ClassReader cr = new ClassReader(in); 36 | ClassWriter cw = new ClassWriter(cr, ClassWriter.COMPUTE_MAXS); 37 | ClassVisitor cv = new ClassVisitor(Opcodes.ASM8, cw) 38 | { 39 | @Override 40 | public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) 41 | { 42 | MethodVisitor mv = cv.visitMethod(access, name, desc, signature, exceptions); 43 | 44 | if (usedMethods.contains(name + desc)) { 45 | System.out.println("Removed unused method: " + name + desc + " in class ==> " + clazz); 46 | // write report to file 47 | myFileWriter.writeDebloatReport(UsageStatusEnum.BLOATED_METHOD.getName(), 48 | clazz + ":" + name + desc, ClassFileType.UNKNOWN); 49 | return new MethodExceptionThrower(mv); 50 | // return null; 51 | } else { 52 | // write report to file 53 | myFileWriter.writeDebloatReport(UsageStatusEnum.USED_METHOD.getName(), 54 | clazz + ":" + name + desc, ClassFileType.UNKNOWN); 55 | } 56 | return mv; 57 | // return super.visitMethod(access, name, desc, signature, exceptions); 58 | } 59 | }; 60 | cr.accept(cv, ClassReader.SKIP_DEBUG); 61 | 62 | byte[] code = cw.toByteArray(); 63 | try (OutputStream fos = new FileOutputStream(outputDirectory + "/" + clazz.replace(".", "/") + ".class")) { 64 | fos.write(code); 65 | } 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /jdbl-core/src/main/java/se/kth/castor/jdbl/util/ZipUtils.java: -------------------------------------------------------------------------------- 1 | package se.kth.castor.jdbl.util; 2 | 3 | //Import all needed packages 4 | 5 | import java.io.File; 6 | import java.io.FileOutputStream; 7 | import java.io.IOException; 8 | import java.io.InputStream; 9 | import java.nio.file.Files; 10 | import java.nio.file.Path; 11 | import java.nio.file.Paths; 12 | import java.util.Enumeration; 13 | import java.util.jar.JarEntry; 14 | import java.util.jar.JarFile; 15 | import java.util.stream.Stream; 16 | import java.util.zip.ZipEntry; 17 | import java.util.zip.ZipOutputStream; 18 | 19 | public class ZipUtils 20 | { 21 | public static void pack(String sourceDirPath, String zipFilePath) throws IOException 22 | { 23 | Path p = Files.createFile(Paths.get(zipFilePath)); 24 | Path pp = Paths.get(sourceDirPath); 25 | try (ZipOutputStream zs = new ZipOutputStream(Files.newOutputStream(p)); 26 | Stream paths = Files.walk(pp)) { 27 | paths 28 | .filter(path -> !Files.isDirectory(path)) 29 | .forEach(path -> { 30 | ZipEntry zipEntry = new ZipEntry(pp.relativize(path).toString()); 31 | try { 32 | zs.putNextEntry(zipEntry); 33 | Files.copy(path, zs); 34 | zs.closeEntry(); 35 | } catch (IOException e) { 36 | System.err.println(e); 37 | } 38 | }); 39 | } 40 | } 41 | 42 | public static void unpack(String destinationDir, String jarPath) throws IOException 43 | { 44 | File file = new File(jarPath); 45 | JarFile jar = new JarFile(file); 46 | 47 | // fist get all directories, 48 | // then make those directory on the destination Path 49 | for (Enumeration enums = jar.entries(); enums.hasMoreElements(); ) { 50 | JarEntry entry = (JarEntry) enums.nextElement(); 51 | 52 | String fileName = destinationDir + File.separator + entry.getName(); 53 | File f = new File(fileName); 54 | 55 | if (fileName.endsWith("/")) { 56 | f.mkdirs(); 57 | } 58 | 59 | } 60 | 61 | //now create all files 62 | for (Enumeration enums = jar.entries(); enums.hasMoreElements(); ) { 63 | JarEntry entry = (JarEntry) enums.nextElement(); 64 | 65 | String fileName = destinationDir + File.separator + entry.getName(); 66 | File f = new File(fileName); 67 | 68 | if (!fileName.endsWith("/")) { 69 | InputStream is = jar.getInputStream(entry); 70 | FileOutputStream fos = new FileOutputStream(f); 71 | 72 | // write contents of 'is' to 'fos' 73 | while (is.available() > 0) { 74 | fos.write(is.read()); 75 | } 76 | 77 | fos.close(); 78 | is.close(); 79 | } 80 | } 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /jdbl-agent/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 4.0.0 7 | jdbl-agent 8 | 1.0.0 9 | 10 | 11 | se.kth.castor 12 | jdbl-parent-pom 13 | 1.0.0 14 | ../ 15 | 16 | 17 | 18 | UTF-8 19 | 20 | 21 | 22 | 23 | 24 | org.apache.maven.plugins 25 | maven-compiler-plugin 26 | 3.8.1 27 | 28 | 11 29 | 11 30 | 31 | 32 | 33 | org.apache.maven.plugins 34 | maven-jar-plugin 35 | 2.4 36 | 37 | 38 | 39 | true 40 | true 41 | true 42 | 43 | 44 | se.kth.castor.jdbl.agent.Agent 45 | false 46 | true 47 | 48 | 49 | 50 | 51 | 52 | maven-assembly-plugin 53 | 54 | 55 | package 56 | 57 | single 58 | 59 | 60 | 61 | 62 | 63 | jar-with-dependencies 64 | 65 | 66 | src/main/resources/META-INF/MANIFEST.MF 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | net.bytebuddy 77 | byte-buddy 78 | 1.10.9 79 | 80 | 81 | 82 | -------------------------------------------------------------------------------- /jdbl-maven-plugin/src/it/dummy-project/src/main/java/defaultmethods/TradingApi.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2015 Gareth Jon Lynch 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy of 7 | * this software and associated documentation files (the "Software"), to deal in 8 | * the Software without restriction, including without limitation the rights to 9 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 10 | * the Software, and to permit persons to whom the Software is furnished to do so, 11 | * subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 18 | * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 19 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 20 | * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 21 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | */ 23 | 24 | package defaultmethods; 25 | 26 | 27 | import java.util.Date; 28 | import java.util.List; 29 | import java.util.UUID; 30 | 31 | import common.Order; 32 | 33 | /** 34 | * A simple, not real-world, part-built Trading API to show use of Java 8 default methods. 35 | * 36 | * @author gazbert 37 | */ 38 | public interface TradingApi { 39 | /** 40 | * Adds an order. 41 | * 42 | * @param order order to add. 43 | * @return true if order placed successfully, false otherwise. 44 | */ 45 | boolean addOrder(Order order); 46 | 47 | /** 48 | * Cancels an order. 49 | * 50 | * @param orderId is of order to cancel. 51 | * @return true if order cancelled successfully, false otherwise. 52 | */ 53 | boolean cancelOrder(UUID orderId); 54 | 55 | /** 56 | * Returns your open orders on the exchange. 57 | * 58 | * @param marketId id of market to fetch orders for. 59 | * @return list of open orders for given market, empty list if none found. 60 | */ 61 | List getOpenOrders(int marketId); 62 | 63 | /* 64 | * Below is the default method. 65 | * This has been added but the interface is already out there and we don't want to break existing code, so we 66 | * provide a default impl. 67 | */ 68 | 69 | /** 70 | * @return the API implementation name. 71 | */ 72 | default String getImplName() { 73 | System.out.println(TradingApi.class.getSimpleName() + " getImplName() called"); 74 | return "Default API Impl"; 75 | } 76 | 77 | /* 78 | * Also new in Java 8 is ability to include staitic methods in the interface. 79 | * 80 | * Note the use of Date - another demo will cover the new Java 8 java.time API :-) 81 | */ 82 | static Date getCurrentExchangeTime() { 83 | return new Date(); 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /jdbl-core/src/test/java/se/kth/castor/jdbl/coverage/JCovCoverageTest.java: -------------------------------------------------------------------------------- 1 | package se.kth.castor.jdbl.coverage; 2 | 3 | import java.io.File; 4 | import java.io.IOException; 5 | 6 | import org.junit.After; 7 | import org.junit.Before; 8 | import org.junit.Test; 9 | 10 | import com.sun.tdk.jcov.Grabber; 11 | import com.sun.tdk.jcov.Instr; 12 | import com.sun.tdk.jcov.JCov; 13 | import com.sun.tdk.jcov.Merger; 14 | import com.sun.tdk.jcov.RepGen; 15 | import com.sun.tdk.jcov.data.Result; 16 | import se.kth.castor.jdbl.util.JarUtils; 17 | import se.kth.castor.jdbl.util.MavenUtils; 18 | 19 | public class JCovCoverageTest 20 | { 21 | private Instr instr; 22 | private RepGen repgen; 23 | private File template; 24 | private Merger merger; 25 | private File classesDir; 26 | private File instrumentedDir; 27 | 28 | @Before 29 | public void setUp() throws Exception 30 | { 31 | instr = new Instr(); 32 | repgen = new RepGen(); 33 | merger = new Merger(); 34 | template = new File("src/test/resources/calc/template.xml"); 35 | classesDir = new File("src/test/resources/calc/"); 36 | instrumentedDir = new File("src/test/resources/calc/inst/"); 37 | } 38 | 39 | @Test 40 | /** 41 | * java -jar jcov.jar tmplgen -t template.xml $path_to_classes 42 | * java -jar jcov.jar grabber -t template.xml -o result_jcov.xml 43 | * run the tests adding javaagent option: "-javaagent:jcov.jar=grabber" 44 | * java -jar jcov.jar grabbermanager -kill 45 | * java -jar jcov.jar repgen -o report result_jcov.xml 46 | * 47 | */ 48 | public void instrument() throws IOException 49 | { 50 | // JCov jCov = new JCov(); 51 | // JCov.main(new String[]{"tmplgen", "t", "template.xml", classesDir.getAbsolutePath()}); 52 | // JCov.printHelp(); 53 | // jCov.run(new String[]{"tmplgen", "t", "template.xml", classesDir.getAbsolutePath()}); 54 | // jCov.run(new String[]{"grabber", "-t", "template.xml", "-o", "result_jcov.xml"}); 55 | 56 | Grabber grabber = new Grabber(); 57 | grabber.createServer(); 58 | grabber.setOutputFilename("myreport.xml"); 59 | grabber.startServer(); 60 | 61 | grabber.stopServer(true); 62 | 63 | 64 | 65 | 66 | // template.getParentFile().mkdirs(); 67 | // instr.config(true, true, true, null, null); 68 | // instr.instrumentFiles(new File[]{classesDir}, instrumentedDir, null); 69 | // instr.finishWork(template.getPath()); 70 | // 71 | // MavenUtils mavenUtils = new MavenUtils(null, null); 72 | // mavenUtils.copyDependency("com.sun.tdk:jcov:1.0", instrumentedDir.getAbsolutePath()); 73 | // JarUtils.decompressJars(instrumentedDir.getAbsolutePath()); 74 | // 75 | // 76 | // final Result result = new Result(template.getAbsolutePath()); 77 | // try { 78 | // repgen.generateReport("src/test/resources/calc/inst/jcov-reports", result); 79 | // } catch (final Exception e) { 80 | // } 81 | 82 | } 83 | 84 | @After 85 | public void tearDown() throws Exception 86 | { 87 | } 88 | 89 | 90 | } 91 | -------------------------------------------------------------------------------- /jdbl-core/src/main/java/se/kth/castor/jdbl/debloat/ConservativeMethodDebloat.java: -------------------------------------------------------------------------------- 1 | package se.kth.castor.jdbl.debloat; 2 | 3 | import java.io.File; 4 | import java.io.FileInputStream; 5 | import java.io.FileOutputStream; 6 | import java.io.IOException; 7 | import java.io.OutputStream; 8 | import java.util.Set; 9 | 10 | import org.objectweb.asm.ClassReader; 11 | import org.objectweb.asm.ClassVisitor; 12 | import org.objectweb.asm.ClassWriter; 13 | import org.objectweb.asm.MethodVisitor; 14 | import org.objectweb.asm.Opcodes; 15 | 16 | import se.kth.castor.jdbl.coverage.UsageAnalysis; 17 | 18 | public class ConservativeMethodDebloat extends AbstractMethodDebloat 19 | { 20 | public ConservativeMethodDebloat(String outputDirectory, UsageAnalysis usageAnalysis, String projectBaseDir) 21 | { 22 | super(outputDirectory, usageAnalysis, projectBaseDir); 23 | } 24 | 25 | @Override 26 | public void removeMethod(String clazz, Set usedMethods) throws IOException 27 | { 28 | try { 29 | FileInputStream in = new FileInputStream(new File(outputDirectory + "/" + clazz + ".class")); 30 | ClassReader cr = new ClassReader(in); 31 | ClassWriter cw = new ClassWriter(cr, ClassWriter.COMPUTE_MAXS); 32 | ClassVisitor cv = new ClassVisitor(Opcodes.ASM8, cw) 33 | { 34 | @Override 35 | public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) 36 | { 37 | MethodVisitor mv = cv.visitMethod(access, name, desc, signature, exceptions); 38 | 39 | if (clazz.equals("calc/Calculator")) { 40 | System.out.println("method name: " + name + ", " + "desc: " + desc + ", " + "signature: " + signature + 41 | ", " + "access: " + access); 42 | System.out.println(usedMethods); 43 | } 44 | 45 | if (isContains(name, usedMethods)) { 46 | // System.out.println("Removing unused method: " + name + desc + " in class: " + clazz); 47 | return new MethodExceptionThrower(mv); 48 | // return null; 49 | } 50 | return mv; 51 | // return super.visitMethod(access, name, desc, signature, exceptions); 52 | } 53 | }; 54 | cr.accept(cv, ClassReader.SKIP_DEBUG); 55 | 56 | byte[] code = cw.toByteArray(); 57 | try (OutputStream fos = new FileOutputStream(outputDirectory + "/" + clazz.replace(".", "/") + ".class")) { 58 | fos.write(code); 59 | } 60 | 61 | } catch (Exception e) { 62 | } // do nothing, just continue analyzing other classes 63 | } 64 | 65 | private boolean isContains(String methodName, Set usedMethods) 66 | { 67 | if (methodName.equals("main")) { 68 | return true; // keep main classes 69 | } 70 | for (String usedMethod : usedMethods) { 71 | if (usedMethod.split("\\(")[0].equals(methodName)) { 72 | return true; 73 | } 74 | } 75 | return false; 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /jdbl-core/src/test/resources/calc/inst/report/overview-summary.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | coverage report 5 | 6 | 7 | 8 | 9 | Coverage report 10 |
11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 |
 #classes%method%block%branch%line
Overall statistics 2
50%(3/6)
50%(3/6)
-%
75%(9/12)
30 |

31 | Packages
32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 |
Name#classes%method%block%branch%line
2
50% (3/6)
50% (3/6)
-
75% (9/12)
50 |
Report generated 6/30/20 1:00 AM
51 | 52 | 53 | -------------------------------------------------------------------------------- /jdbl-core/src/main/java/se/kth/castor/jdbl/test/TestRunner.java: -------------------------------------------------------------------------------- 1 | package se.kth.castor.jdbl.test; 2 | 3 | import java.io.BufferedReader; 4 | import java.io.IOException; 5 | import java.io.InputStreamReader; 6 | 7 | import org.apache.log4j.LogManager; 8 | import org.apache.log4j.Logger; 9 | import org.apache.maven.project.MavenProject; 10 | 11 | import se.kth.castor.jdbl.coverage.YajtaCoverage; 12 | import se.kth.castor.jdbl.util.MyFileWriter; 13 | 14 | public class TestRunner 15 | { 16 | private static final Logger LOGGER = LogManager.getLogger(TestRunner.class.getName()); 17 | 18 | public static void runTests(MavenProject mavenProject, boolean isTestRunForCoverage) throws IOException 19 | { 20 | Runtime rt = Runtime.getRuntime(); 21 | Process p; 22 | 23 | if (isTestRunForCoverage) { 24 | p = rt.exec("mvn org.apache.maven.plugins:maven-surefire-plugin:3.0.0-M5:test"); 25 | } else { 26 | p = rt.exec("mvn test -Dmaven.main.skip=true -Drat.skip=true -Danimal.sniffer.skip=true -Dmaven.javadoc.skip=true -Dlicense.skip=true -Dsource.skip=true"); 27 | } 28 | 29 | printProcessToStandardOutput(p); 30 | 31 | try { 32 | p.waitFor(); 33 | } catch ( 34 | InterruptedException e) { 35 | LOGGER.error("Re-testing process terminated unexpectedly."); 36 | Thread.currentThread().interrupt(); 37 | } 38 | 39 | TestResultReader testResultReader = new TestResultReader("."); 40 | TestResult testResult = testResultReader.getResults(); 41 | 42 | MyFileWriter myFileWriter = new MyFileWriter(mavenProject.getBasedir().getAbsolutePath()); 43 | myFileWriter.writeTestResultsToFile(testResult); 44 | 45 | if (testResult.errorTests() != 0 || testResult.failedTests() != 0) { 46 | LOGGER.error("JDBL: THERE ARE TESTS FAILURES"); 47 | } 48 | } 49 | 50 | public static void runTests2(MavenProject mavenProject, String template) throws IOException 51 | { 52 | Runtime rt = Runtime.getRuntime(); 53 | Process p; 54 | 55 | p = rt.exec("mvn surefire:test " + 56 | "-DargLine=\"-Djcov.template=" + template + "\""); 57 | 58 | printProcessToStandardOutput(p); 59 | 60 | try { 61 | p.waitFor(); 62 | } catch ( 63 | InterruptedException e) { 64 | LOGGER.error("Re-testing process terminated unexpectedly."); 65 | Thread.currentThread().interrupt(); 66 | } 67 | 68 | TestResultReader testResultReader = new TestResultReader("."); 69 | TestResult testResult = testResultReader.getResults(); 70 | 71 | MyFileWriter myFileWriter = new MyFileWriter(mavenProject.getBasedir().getAbsolutePath()); 72 | myFileWriter.writeTestResultsToFile(testResult); 73 | 74 | if (testResult.errorTests() != 0 || testResult.failedTests() != 0) { 75 | LOGGER.error("JDBL: THERE ARE TESTS FAILURES"); 76 | } 77 | 78 | } 79 | 80 | private static void printProcessToStandardOutput(final Process p) throws IOException 81 | { 82 | String line; 83 | BufferedReader input = new BufferedReader(new InputStreamReader(p.getInputStream())); 84 | while ((line = input.readLine()) != null) { 85 | System.out.println(line); 86 | } 87 | input.close(); 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /jdbl-core/src/test/resources/calc/template.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 0=8;4=9;9=10;14=11; 39 | 40 | 41 | 42 | 43 | 44 | 45 | 0=14; 46 | 47 | 48 | 49 | 50 | 51 | 52 | 0=18; 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 0=1; 62 | 63 | 64 | 65 | 66 | 67 | 68 | 0=6;10=7;15=8;40=9; 69 | 70 | 71 | 72 | 73 | 74 | 75 | 0=13; 76 | 77 | 78 | 79 | 80 | -------------------------------------------------------------------------------- /jdbl-core/src/test/resources/calc/inst/result.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 0=8;4=9;9=10;14=11; 39 | 40 | 41 | 42 | 43 | 44 | 45 | 0=14; 46 | 47 | 48 | 49 | 50 | 51 | 52 | 0=18; 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 0=1; 62 | 63 | 64 | 65 | 66 | 67 | 68 | 0=6;10=7;15=8;40=9; 69 | 70 | 71 | 72 | 73 | 74 | 75 | 0=13; 76 | 77 | 78 | 79 | 80 | -------------------------------------------------------------------------------- /jdbl-core/src/test/resources/calc/inst/template.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 0=8;4=9;9=10;14=11; 39 | 40 | 41 | 42 | 43 | 44 | 45 | 0=14; 46 | 47 | 48 | 49 | 50 | 51 | 52 | 0=18; 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 0=1; 62 | 63 | 64 | 65 | 66 | 67 | 68 | 0=6;10=7;15=8;40=9; 69 | 70 | 71 | 72 | 73 | 74 | 75 | 0=13; 76 | 77 | 78 | 79 | 80 | -------------------------------------------------------------------------------- /jdbl-core/src/test/resources/coverage/result_jcov.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 0=8;4=9;9=10;14=11; 39 | 40 | 41 | 42 | 43 | 44 | 45 | 0=14; 46 | 47 | 48 | 49 | 50 | 51 | 52 | 0=18; 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 0=1; 62 | 63 | 64 | 65 | 66 | 67 | 68 | 0=6;10=7;15=8;40=9; 69 | 70 | 71 | 72 | 73 | 74 | 75 | 0=13; 76 | 77 | 78 | 79 | 80 | -------------------------------------------------------------------------------- /jdbl-maven-plugin/src/main/java/se/kth/castor/jdbl/plugin/ConservativeDebloatMojo.java: -------------------------------------------------------------------------------- 1 | package se.kth.castor.jdbl.plugin; 2 | 3 | import java.io.File; 4 | import java.io.IOException; 5 | import java.util.HashSet; 6 | import java.util.Objects; 7 | import java.util.Set; 8 | 9 | import org.apache.maven.plugins.annotations.LifecyclePhase; 10 | import org.apache.maven.plugins.annotations.Mojo; 11 | 12 | import se.kth.castor.jdbl.callgraph.JCallGraphModified; 13 | import se.kth.castor.jdbl.coverage.UsageAnalysis; 14 | import se.kth.castor.jdbl.debloat.AbstractMethodDebloat; 15 | import se.kth.castor.jdbl.debloat.ConservativeMethodDebloat; 16 | import se.kth.castor.jdbl.util.MyFileUtils; 17 | import se.kth.castor.jdbl.util.JarUtils; 18 | import se.kth.castor.jdbl.util.MavenUtils; 19 | 20 | /** 21 | * This Maven mojo statically instruments the project and its dependencies in order to remove unused API members. 22 | */ 23 | @Mojo(name = "conservative-debloat", defaultPhase = LifecyclePhase.PREPARE_PACKAGE, threadSafe = true) 24 | public class ConservativeDebloatMojo extends AbstractDebloatMojo 25 | { 26 | @Override 27 | public void doExecute() 28 | { 29 | printCustomStringToConsole("S T A R T I N G C O N S E R V A T I V E D E B L O A T"); 30 | 31 | String outputDirectory = getProject().getBuild().getOutputDirectory(); 32 | File baseDir = getProject().getBasedir(); 33 | 34 | MavenUtils mavenUtils = new MavenUtils(getMavenHome(), baseDir); 35 | 36 | // copy the dependencies 37 | mavenUtils.copyRuntimeDependencies(outputDirectory); 38 | 39 | // copy the resources 40 | mavenUtils.copyResources(outputDirectory); 41 | 42 | // decompress the copied dependencies 43 | JarUtils.decompressJars(outputDirectory); 44 | 45 | JCallGraphModified jCallGraphModified = new JCallGraphModified(); 46 | 47 | // run de static usage analysis 48 | UsageAnalysis usageAnalysis = jCallGraphModified 49 | .runUsageAnalysis(getProject().getBuild().getOutputDirectory()); 50 | 51 | Set classesUsed = usageAnalysis.getAnalysis().keySet(); 52 | 53 | this.getLog().info(String.format("#Total classes: %d", 54 | (long) usageAnalysis.getAnalysis().entrySet().size())); 55 | this.getLog().info(String.format("#Unused classes: %d", 56 | usageAnalysis.getAnalysis().entrySet().stream().filter(e -> e.getValue() == null).count())); 57 | this.getLog().info(String.format("#Unused methods: %d", 58 | usageAnalysis.getAnalysis().values().stream().filter(Objects::nonNull).mapToInt(Set::size).sum())); 59 | 60 | // delete unused classes 61 | MyFileUtils MyFileUtils = new MyFileUtils(outputDirectory, 62 | new HashSet<>(), 63 | classesUsed, 64 | getProject().getBasedir().getAbsolutePath(), null); 65 | try { 66 | MyFileUtils.deleteUnusedClasses(outputDirectory); 67 | } catch (IOException e) { 68 | this.getLog().error(String.format("Error deleting unused classes: %s", e)); 69 | } 70 | 71 | // delete unused methods 72 | AbstractMethodDebloat conservativeMethodDebloat = new ConservativeMethodDebloat(outputDirectory, 73 | usageAnalysis, 74 | getProject().getBasedir().getAbsolutePath() + "/.jdbl/debloat-report.csv"); 75 | try { 76 | conservativeMethodDebloat.removeUnusedMethods(); 77 | } catch (IOException e) { 78 | this.getLog().error(String.format("Error: %s", e)); 79 | } 80 | 81 | printCustomStringToConsole("C O N S E R V A T I V E D E B L O A T F I N I S H E D"); 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /jdbl-core/src/test/resources/calc/inst/report/package-summary.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | coverage report 5 | 6 | 7 | 8 | 9 | Coverage report 10 |
11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 |
 #classes%method%block%branch%line
2
50%(3/6)
50%(3/6)
-%
75%(9/12)
30 |

31 | Classes
32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 |
Name%method%block%branch%line
Calc
67% (2/3)
67% (2/3)
-
83% (5/6)
Main
33% (1/3)
33% (1/3)
-
67% (4/6)
55 |
Report generated 6/30/20 1:00 AM
56 | 57 | 58 | -------------------------------------------------------------------------------- /jdbl-core/src/main/java/se/kth/castor/jdbl/callgraph/ClassVisitor.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2011 - Georgios Gousios 3 | * 4 | * Redistribution and use in source and binary forms, with or without 5 | * modification, are permitted provided that the following conditions are 6 | * met: 7 | * 8 | * * Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * 11 | * * Redistributions in binary form must reproduce the above 12 | * copyright notice, this list of conditions and the following 13 | * disclaimer in the documentation and/or other materials provided 14 | * with the distribution. 15 | * 16 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | */ 28 | 29 | package se.kth.castor.jdbl.callgraph; 30 | 31 | import java.util.LinkedList; 32 | import java.util.List; 33 | 34 | import org.apache.bcel.classfile.Constant; 35 | import org.apache.bcel.classfile.ConstantPool; 36 | import org.apache.bcel.classfile.EmptyVisitor; 37 | import org.apache.bcel.classfile.JavaClass; 38 | import org.apache.bcel.classfile.Method; 39 | import org.apache.bcel.generic.ConstantPoolGen; 40 | import org.apache.bcel.generic.MethodGen; 41 | 42 | /** 43 | * The simplest of class visitors, invokes the method visitor class for each 44 | * method found. 45 | */ 46 | public class ClassVisitor extends EmptyVisitor 47 | { 48 | private JavaClass clazz; 49 | private ConstantPoolGen constants; 50 | private String classReferenceFormat; 51 | private final DynamicCallManager dynamicCallManager = new DynamicCallManager(); 52 | private List methodCalls = new LinkedList<>(); 53 | 54 | public ClassVisitor(JavaClass jc) 55 | { 56 | clazz = jc; 57 | constants = new ConstantPoolGen(clazz.getConstantPool()); 58 | classReferenceFormat = "C:" + clazz.getClassName() + " %s"; 59 | } 60 | 61 | @Override 62 | public void visitJavaClass(JavaClass jc) 63 | { 64 | jc.getConstantPool().accept(this); 65 | Method[] methods = jc.getMethods(); 66 | for (Method method : methods) { 67 | dynamicCallManager.retrieveCalls(method, jc); 68 | dynamicCallManager.linkCalls(method); 69 | method.accept(this); 70 | } 71 | } 72 | 73 | @Override 74 | public void visitConstantPool(ConstantPool constantPool) 75 | { 76 | for (int i = 0; i < constantPool.getLength(); i++) { 77 | Constant constant = constantPool.getConstant(i); 78 | if (constant == null) { 79 | continue; 80 | } 81 | if (constant.getTag() == 7) { 82 | String referencedClass = constantPool.constantToString(constant); 83 | // System.out.println(String.format(classReferenceFormat, referencedClass)); 84 | } 85 | } 86 | } 87 | 88 | @Override 89 | public void visitMethod(Method method) 90 | { 91 | MethodGen mg = new MethodGen(method, clazz.getClassName(), constants); 92 | MethodVisitor visitor = new MethodVisitor(mg, clazz); 93 | methodCalls.addAll(visitor.start()); 94 | } 95 | 96 | public ClassVisitor start() 97 | { 98 | visitJavaClass(clazz); 99 | return this; 100 | } 101 | 102 | public List methodCalls() 103 | { 104 | return this.methodCalls; 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /jdbl-core/src/main/java/se/kth/castor/jdbl/coverage/JVMClassCoverage.java: -------------------------------------------------------------------------------- 1 | package se.kth.castor.jdbl.coverage; 2 | 3 | import java.io.BufferedReader; 4 | import java.io.File; 5 | import java.io.IOException; 6 | import java.io.InputStreamReader; 7 | import java.util.ArrayList; 8 | import java.util.Arrays; 9 | import java.util.HashSet; 10 | import java.util.List; 11 | import java.util.Map; 12 | import java.util.Set; 13 | 14 | import org.apache.log4j.LogManager; 15 | import org.apache.maven.project.MavenProject; 16 | 17 | import se.kth.castor.jdbl.debloat.DebloatTypeEnum; 18 | 19 | public class JVMClassCoverage extends AbstractCoverage 20 | { 21 | public JVMClassCoverage(MavenProject mavenProject, File mavenHome, DebloatTypeEnum debloatTypeEnum) 22 | { 23 | super(mavenProject, mavenHome, debloatTypeEnum); 24 | LOGGER = LogManager.getLogger(JVMClassCoverage.class.getName()); 25 | } 26 | 27 | protected UsageAnalysis executeTestBasedAnalysis() 28 | { 29 | try { 30 | writeCoverage(); 31 | } catch (IOException e) { 32 | LOGGER.info("Error writing JVM usage analysis."); 33 | } 34 | UsageAnalysis usageAnalysis = new UsageAnalysis(); 35 | Set classesLoaded = JVMClassesCoveredSingleton.INSTANCE.getClassesLoaded(); 36 | for (String classLoaded : classesLoaded) { 37 | usageAnalysis.addEntry(classLoaded, new HashSet<>(Arrays.asList("UNKNOWN"))); 38 | } 39 | 40 | return usageAnalysis; 41 | } 42 | 43 | public void writeCoverage() throws IOException 44 | { 45 | LOGGER.info("Starting executing tests in verbose mode to get JVM class loader report."); 46 | Set classesLoadedTestDebloat = new HashSet<>(); 47 | List args = new ArrayList<>(); 48 | args.add("mvn"); 49 | args.add("surefire:test"); 50 | args.add("-X"); 51 | args.add("-DargLine=@{argLine}"); 52 | args.add("-DargLine=-verbose:class"); 53 | ProcessBuilder processBuilder = new ProcessBuilder(args); 54 | Map environment = processBuilder.environment(); 55 | environment.put("JAVA_HOME", System.getenv().get("JAVA_HOME")); 56 | Process p = processBuilder.start(); 57 | new Thread(() -> { 58 | BufferedReader input = new BufferedReader(new InputStreamReader(p.getInputStream())); 59 | String line; 60 | try { 61 | while ((line = input.readLine()) != null) { 62 | if ((line.contains("class,load") && line.endsWith("target/classes/")) || 63 | (line.contains("[Loaded") && line.endsWith("target/classes/]"))) { 64 | classesLoadedTestDebloat.add(line.split(" ")[1]); 65 | } 66 | } 67 | } catch (IOException e) { 68 | LOGGER.error("Error parsing line."); 69 | } 70 | input = new BufferedReader(new InputStreamReader(p.getErrorStream())); 71 | try { 72 | while ((line = input.readLine()) != null) { 73 | LOGGER.info(line); 74 | } 75 | } catch (IOException e) { 76 | LOGGER.error("Error reading line."); 77 | } 78 | }).start(); 79 | 80 | try { 81 | p.waitFor(); 82 | } catch (InterruptedException e) { 83 | Thread.currentThread().interrupt(); 84 | } 85 | 86 | // print info about the number of classes loaded 87 | JVMClassesCoveredSingleton.INSTANCE.setClassesLoaded(classesLoadedTestDebloat); 88 | } 89 | 90 | protected UsageAnalysis executeConservativeAnalysis() 91 | { 92 | // TODO implement the conservative approach 93 | return null; 94 | } 95 | 96 | protected UsageAnalysis executeEntryPointAnalysis() 97 | { 98 | // TODO implement the entry point approach 99 | LOGGER.info("Output directory: " + mavenProject.getBuild().getOutputDirectory()); 100 | LOGGER.info("entryClass: " + entryClass); 101 | LOGGER.info("entryMethod: " + entryMethod); 102 | LOGGER.info("entryParameters: " + entryParameters); 103 | return null; 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /jdbl-core/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 4.0.0 6 | 7 | se.kth.castor 8 | jdbl-core 9 | 1.0.0 10 | 11 | 12 | se.kth.castor 13 | jdbl-parent-pom 14 | 1.0.0 15 | ../ 16 | 17 | 18 | jdbl-core 19 | https://github.com/castor-software/royal-debloat/jdbl/jdbl-maven-plugin 20 | 21 | 22 | UTF-8 23 | 11 24 | 11 25 | 26 | 27 | 28 | 29 | 30 | org.apache.maven 31 | maven-core 32 | 3.6.0 33 | 34 | 35 | org.apache.maven 36 | maven-plugin-api 37 | 3.6.0 38 | 39 | 40 | org.apache.maven.shared 41 | maven-invoker 42 | 3.0.1 43 | 44 | 45 | 46 | 47 | org.ow2.asm 48 | asm 49 | 9.3 50 | 51 | 52 | org.ow2.asm 53 | asm-util 54 | 9.3 55 | 56 | 57 | org.apache.bcel 58 | bcel 59 | 6.3.1 60 | compile 61 | 62 | 63 | 64 | 65 | org.apache.logging.log4j 66 | log4j-api 67 | 2.13.1 68 | 69 | 70 | org.apache.logging.log4j 71 | log4j-core 72 | 2.13.2 73 | 74 | 75 | log4j 76 | log4j 77 | 1.2.17 78 | 79 | 80 | 81 | 82 | com.fasterxml.jackson.core 83 | jackson-databind 84 | 2.10.0.pr1 85 | 86 | 87 | se.kth.castor 88 | yajta-lean 89 | 2.0.2 90 | 91 | 92 | 93 | 94 | org.jacoco 95 | org.jacoco.core 96 | 0.8.5 97 | 98 | 99 | org.jacoco 100 | org.jacoco.report 101 | 0.8.5 102 | 103 | 104 | 105 | 106 | com.sun.tdk 107 | jcov 108 | 1.0 109 | 110 | 111 | 112 | 113 | 114 | 115 | org.junit.jupiter 116 | junit-jupiter-engine 117 | 5.6.1 118 | test 119 | 120 | 121 | org.junit.platform 122 | junit-platform-runner 123 | 1.6.1 124 | test 125 | 126 | 127 | 128 | -------------------------------------------------------------------------------- /jdbl-maven-plugin/src/main/java/se/kth/castor/jdbl/plugin/EntryPointDebloatMojo.java: -------------------------------------------------------------------------------- 1 | package se.kth.castor.jdbl.plugin; 2 | 3 | import java.io.File; 4 | import java.io.IOException; 5 | import java.util.HashSet; 6 | import java.util.Objects; 7 | import java.util.Set; 8 | 9 | import org.apache.maven.plugins.annotations.LifecyclePhase; 10 | import org.apache.maven.plugins.annotations.Mojo; 11 | import org.apache.maven.plugins.annotations.Parameter; 12 | 13 | import se.kth.castor.jdbl.coverage.AbstractCoverage; 14 | import se.kth.castor.jdbl.coverage.JVMClassesCoveredSingleton; 15 | import se.kth.castor.jdbl.coverage.JacocoCoverage; 16 | import se.kth.castor.jdbl.coverage.UsageAnalysis; 17 | import se.kth.castor.jdbl.debloat.AbstractMethodDebloat; 18 | import se.kth.castor.jdbl.debloat.DebloatTypeEnum; 19 | import se.kth.castor.jdbl.debloat.EntryPointMethodDebloat; 20 | import se.kth.castor.jdbl.util.JarUtils; 21 | import se.kth.castor.jdbl.util.MavenUtils; 22 | import se.kth.castor.jdbl.util.MyFileUtils; 23 | 24 | /** 25 | * This Maven mojo instruments the project according to an entry point provided as parameters in Maven configuration. 26 | * Probes are inserted in order to keep track of the classes and methods used. 27 | * Non covered elements are removed from the final bundled jar file. 28 | */ 29 | @Mojo(name = "entry-point-debloat", defaultPhase = LifecyclePhase.PREPARE_PACKAGE, threadSafe = true) 30 | public class EntryPointDebloatMojo extends AbstractDebloatMojo 31 | { 32 | @Parameter(property = "entry.class", name = "entryClass", required = true) 33 | private String entryClass = ""; 34 | 35 | @Parameter(property = "entry.method", name = "entryMethod", required = true) 36 | private String entryMethod = ""; 37 | 38 | @Parameter(property = "entry.parameters", name = "entryParameters", defaultValue = " ") 39 | private String entryParameters = null; 40 | 41 | @Override 42 | public void doExecute() 43 | { 44 | printCustomStringToConsole("S T A R T I N G E N T R Y P O I N T D E B L O A T"); 45 | 46 | String outputDirectory = getProject().getBuild().getOutputDirectory(); 47 | File baseDir = getProject().getBasedir(); 48 | 49 | MavenUtils mavenUtils = new MavenUtils(getMavenHome(), baseDir); 50 | 51 | // copy the dependencies 52 | mavenUtils.copyRuntimeDependencies(outputDirectory); 53 | 54 | // copy the resources 55 | mavenUtils.copyResources(outputDirectory); 56 | 57 | // decompress the copied dependencies 58 | JarUtils.decompressJars(outputDirectory); 59 | 60 | // getting the used methods 61 | AbstractCoverage jacocoCoverage = new JacocoCoverage( 62 | getProject(), 63 | mavenHome, 64 | DebloatTypeEnum.ENTRY_POINT_DEBLOAT, 65 | this.entryClass, 66 | this.entryMethod, 67 | this.entryParameters); 68 | 69 | UsageAnalysis usageAnalysis = null; 70 | 71 | // run the usage analysis 72 | usageAnalysis = jacocoCoverage.analyzeUsages(); 73 | // print some results 74 | this.getLog().info(String.format("#Unused classes: %d", 75 | usageAnalysis.getAnalysis().entrySet().stream().filter(e -> e.getValue() == null).count())); 76 | this.getLog().info(String.format("#Unused methods: %d", 77 | usageAnalysis.getAnalysis().values().stream().filter(Objects::nonNull).mapToInt(Set::size).sum())); 78 | 79 | // remove unused classes 80 | MyFileUtils myFileUtils = new MyFileUtils(outputDirectory, new HashSet<>(), 81 | JVMClassesCoveredSingleton.INSTANCE.getClassesLoaded(), 82 | getProject().getBasedir().getAbsolutePath(), null); 83 | try { 84 | myFileUtils.deleteUnusedClasses(outputDirectory); 85 | } catch (IOException e) { 86 | this.getLog().error(String.format("Error deleting unused classes: %s", e)); 87 | } 88 | 89 | // remove unused methods 90 | AbstractMethodDebloat entryPointMethodDebloat = new EntryPointMethodDebloat(outputDirectory, 91 | usageAnalysis, 92 | getProject().getBasedir().getAbsolutePath() + "/.jdbl/debloat-report.csv"); 93 | try { 94 | entryPointMethodDebloat.removeUnusedMethods(); 95 | } catch (IOException e) { 96 | this.getLog().error(String.format("Error: %s", e)); 97 | } 98 | printCustomStringToConsole("E N T R Y P O I N T D E B L O A T F I N I S H E D"); 99 | } 100 | } 101 | 102 | 103 | -------------------------------------------------------------------------------- /jdbl-maven-plugin/src/it/dummy-project/src/main/java/common/Order.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2015 Gareth Jon Lynch 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy of 7 | * this software and associated documentation files (the "Software"), to deal in 8 | * the Software without restriction, including without limitation the rights to 9 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 10 | * the Software, and to permit persons to whom the Software is furnished to do so, 11 | * subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 18 | * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 19 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 20 | * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 21 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | */ 23 | 24 | package common; 25 | 26 | import java.math.BigDecimal; 27 | import java.util.UUID; 28 | 29 | /** 30 | * Models an order for placing on an exchange. 31 | * 32 | * @author gazbert 33 | */ 34 | public class Order { 35 | 36 | /** 37 | * Defines the martket ids. 38 | * 39 | * @author gazbert 40 | */ 41 | public enum Market { 42 | /** 43 | * Dollar 44 | */ 45 | USD, 46 | 47 | /** 48 | * Yuan 49 | */ 50 | CNY, 51 | 52 | /** 53 | * Euro 54 | */ 55 | EUR 56 | } 57 | 58 | /** 59 | * Defines the types of order. 60 | * 61 | * @author gazbert 62 | */ 63 | public enum Type { 64 | /** 65 | * BUY order 66 | */ 67 | BUY, 68 | 69 | /** 70 | * SELL order 71 | */ 72 | SELL 73 | } 74 | 75 | /** 76 | * Id 77 | */ 78 | private UUID id; 79 | 80 | /** 81 | * Market id 82 | */ 83 | private Market marketId; 84 | 85 | /** 86 | * Type of order BUY|SELL 87 | */ 88 | private Type type; 89 | 90 | /** 91 | * Amount of units in the order 92 | */ 93 | private BigDecimal amount; 94 | 95 | /** 96 | * Price per unit of order 97 | */ 98 | private BigDecimal price; 99 | 100 | /** 101 | * Fee 102 | */ 103 | private BigDecimal fee; 104 | 105 | /** 106 | * Number of trades it took to fill the order 107 | */ 108 | private int tradeCountToFill; 109 | 110 | 111 | /** 112 | * Constructor builds an order. 113 | * 114 | * @param marketId the market id. 115 | * @param type the order type 116 | * @param amount the order amount. 117 | * @param price the order price. 118 | * @param fee the order fee. 119 | */ 120 | public Order(Market marketId, Type type, BigDecimal amount, BigDecimal price, BigDecimal fee) { 121 | 122 | this.marketId = marketId; 123 | this.type = type; 124 | this.amount = amount; 125 | this.price = price; 126 | this.fee = fee; 127 | 128 | id = UUID.randomUUID(); 129 | } 130 | 131 | public UUID getId() { 132 | return id; 133 | } 134 | 135 | public Market getMarketId() { 136 | return marketId; 137 | } 138 | 139 | public Type getType() { 140 | return type; 141 | } 142 | 143 | public BigDecimal getAmount() { 144 | return amount; 145 | } 146 | 147 | public BigDecimal getPrice() { 148 | return price; 149 | } 150 | 151 | public BigDecimal getFee() { 152 | return fee; 153 | } 154 | 155 | /** 156 | * Returns the order details required for auditing. 157 | * 158 | * @return audit details. 159 | */ 160 | public String provideAuditDetails() { 161 | // keep it simple for the demo. 162 | return "OrderId: " + id + " Market: " + marketId + " Amount: " + amount + " Price: " + price; 163 | } 164 | 165 | public int getTradeCountToFill() { 166 | return tradeCountToFill; 167 | } 168 | 169 | public void setTradeCountToFill(int tradeCountToFill) { 170 | this.tradeCountToFill = tradeCountToFill; 171 | } 172 | } 173 | -------------------------------------------------------------------------------- /jdbl-core/src/test/resources/jcov/report.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 0=8;4=9;9=10;14=11; 39 | 40 | 41 | 42 | 43 | 44 | 45 | 0=15; 46 | 47 | 48 | 49 | 50 | 51 | 52 | 0=20; 53 | 54 | 55 | 56 | 57 | 58 | 59 | 0=25; 60 | 61 | 62 | 63 | 64 | 65 | 66 | 0=29; 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 0=3; 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 0=5;5=6; 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 0=3; 94 | 95 | 96 | 97 | 98 | 99 | 100 | 0=6;20=7;50=8; 101 | 102 | 103 | 104 | 105 | -------------------------------------------------------------------------------- /jdbl-core/src/main/java/se/kth/castor/jdbl/deptree/AbstractParser.java: -------------------------------------------------------------------------------- 1 | package se.kth.castor.jdbl.deptree; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | public abstract class AbstractParser implements Parser 7 | { 8 | /** 9 | * Parses a string representing a Maven artifact in standard notation. 10 | * 11 | * @param artifact the artifact 12 | * @return an instance of {@link Node} representing the artifact. 13 | */ 14 | protected Node parseArtifactString(final String artifact) 15 | { 16 | final List tokens = new ArrayList<>(7); 17 | int tokenStart = 0; 18 | boolean tokenStarted = false; 19 | boolean hasDescription = false; 20 | boolean omitted = false; 21 | int tokenEnd = 0; 22 | for (; tokenEnd < artifact.length(); tokenEnd++) { 23 | final char c = artifact.charAt(tokenEnd); 24 | switch (c) { 25 | case ' ': // in descriptions only 26 | if (tokenStarted && !hasDescription) { 27 | tokens.add(artifact.substring(tokenStart, tokenEnd)); 28 | tokenStarted = false; 29 | hasDescription = true; 30 | } 31 | continue; 32 | 33 | case ':': 34 | case ')': //end of descriptions and omitted artifacts 35 | tokens.add(artifact.substring(tokenStart, tokenEnd)); 36 | tokenStarted = false; 37 | continue; 38 | 39 | case '-': // in omitted artifacts descriptions 40 | continue; 41 | 42 | case '(': // in omitted artifacts 43 | if (tokenEnd == 0) { 44 | omitted = true; 45 | } 46 | continue; 47 | 48 | default: 49 | if (!tokenStarted) { 50 | tokenStart = tokenEnd; 51 | tokenStarted = true; 52 | } 53 | continue; 54 | } 55 | } 56 | 57 | //last token 58 | if (tokenStarted) { 59 | tokens.add(artifact.substring(tokenStart, tokenEnd)); 60 | } 61 | 62 | String groupId; 63 | String artifactId; 64 | String packaging; 65 | String classifier; 66 | String version; 67 | String scope; 68 | String description; 69 | 70 | if (tokens.size() == 3) { 71 | groupId = tokens.get(0); 72 | artifactId = tokens.get(1); 73 | version = tokens.get(2); 74 | packaging = null; 75 | scope = null; 76 | description = null; 77 | classifier = null; 78 | 79 | } else if (tokens.size() == 4) { 80 | 81 | groupId = tokens.get(0); 82 | artifactId = tokens.get(1); 83 | packaging = tokens.get(2); 84 | version = tokens.get(3); 85 | scope = null; 86 | description = null; 87 | classifier = null; 88 | 89 | } else if (tokens.size() == 5) { 90 | 91 | groupId = tokens.get(0); 92 | artifactId = tokens.get(1); 93 | packaging = tokens.get(2); 94 | version = tokens.get(3); 95 | scope = tokens.get(4); 96 | description = null; 97 | classifier = null; 98 | 99 | } else if (tokens.size() == 6) { 100 | 101 | if (hasDescription) { 102 | groupId = tokens.get(0); 103 | artifactId = tokens.get(1); 104 | packaging = tokens.get(2); 105 | version = tokens.get(3); 106 | scope = tokens.get(4); 107 | description = tokens.get(5); 108 | classifier = null; 109 | } else { 110 | groupId = tokens.get(0); 111 | artifactId = tokens.get(1); 112 | packaging = tokens.get(2); 113 | classifier = tokens.get(3); 114 | version = tokens.get(4); 115 | scope = tokens.get(5); 116 | description = null; 117 | } 118 | 119 | } else if (tokens.size() == 7) { 120 | groupId = tokens.get(0); 121 | artifactId = tokens.get(1); 122 | packaging = tokens.get(2); 123 | classifier = tokens.get(3); 124 | version = tokens.get(4); 125 | scope = tokens.get(5); 126 | description = tokens.get(6); 127 | 128 | } else { 129 | throw new IllegalStateException("Wrong number of tokens: " + tokens.size() + " for artifact: " + artifact); 130 | } 131 | 132 | return new Node(groupId, artifactId, packaging, classifier, version, scope, description, omitted); 133 | } 134 | } 135 | -------------------------------------------------------------------------------- /jdbl-core/src/test/resources/calc/inst/report/Calc.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | tests coverage 5 | 6 | 7 | 52 | 53 | 54 | 55 | 56 | 60 | 61 |
57 | Frames 58 | No Frames 59 |
62 |
63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 |
 %method%block%branch%line
Calc
67%(2/3)
67%(2/3)
-%
83%(5/6)
79 |
80 |
81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 |
hit countmethod namemethod modifiersmethod signature
1<init>[public]void <init>(int,int)
0rest[public]int rest()
1sum[public]int sum()
107 |
108 |

109 |
Report generated 6/30/20 1:00 AM
110 | 111 | 112 | -------------------------------------------------------------------------------- /jdbl-core/src/test/resources/calc/inst/report/Main.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | tests coverage 5 | 6 | 7 | 52 | 53 | 54 | 55 | 56 | 60 | 61 |
57 | Frames 58 | No Frames 59 |
62 |
63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 |
 %method%block%branch%line
Main
33%(1/3)
33%(1/3)
-%
67%(4/6)
79 |
80 |
81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 |
hit countmethod namemethod modifiersmethod signature
0<init>[public]void <init>()
0anotherSum[private, static]int anotherSum(int,int)
1main[public, static]void main(java.lang.String[])
107 |
108 |

109 |
Report generated 6/30/20 1:00 AM
110 | 111 | 112 | -------------------------------------------------------------------------------- /jdbl-maven-plugin/src/it/dummy-project/src/main/java/lambda/LambdaScoping.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2015 Gareth Jon Lynch 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy of 7 | * this software and associated documentation files (the "Software"), to deal in 8 | * the Software without restriction, including without limitation the rights to 9 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 10 | * the Software, and to permit persons to whom the Software is furnished to do so, 11 | * subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 18 | * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 19 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 20 | * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 21 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | */ 23 | 24 | package lambda; 25 | 26 | import java.util.function.Consumer; 27 | 28 | /** 29 | * Demonstrates lambda scoping. Based on the example in the Java 8 tutorial. 30 | *

31 | * Lambdas capture variables like local and anonymous classes. In other words, they have the same access to 32 | * local variables of the enclosing scope. 33 | *

34 | * One key difference though, is that lambdas do not suffer from shadowing issues, e.g. where a local class 35 | * has the same variable and that is used in place of/hides the variable in the outer scope. 36 | *

37 | * Lambda expressions are lexically scoped: they do not inherit any names from a supertype or introduce a new level of 38 | * scoping. 39 | *

40 | * See the example below. 41 | * 42 | * @author gazbert 43 | */ 44 | public class LambdaScoping 45 | { 46 | 47 | /** 48 | * Outermost level scoped x arg 49 | */ 50 | public int x = 1; // 3 // change this to 3 and LambdaScoping.this.x sysout will print 3 51 | 52 | /** 53 | * First level nested class. 54 | * 55 | * @author gazbert 56 | */ 57 | class FirstLevel 58 | { 59 | /** 60 | * First level scoped x arg 61 | */ 62 | public int x = 2; // 5 // change this to 5 and this.x sysout will print 5 63 | 64 | /** 65 | * x arg is passed in by the caller. 66 | * 67 | * @param x 68 | */ 69 | void methodInFirstLevel(int x) 70 | { 71 | /* 72 | * The following statement causes the compiler to generate 73 | * the error "Local variable x defined in an enclosing scope must be final or effectively final" 74 | * 75 | * Like local and anonymous classes, a lambda expression can only access local variables and parameters of 76 | * the enclosing block that are final or effectively final. 77 | */ 78 | //x = 99; 79 | 80 | /* 81 | * Our lambda uses JDK standard Consumer functional interface. 82 | * More details on standard functions here: 83 | * http://download.java.net/lambda/b81/docs/api/java/util/function/package-summary.html 84 | * 85 | * If you change y arg to be x arg, compiler will error "Lambda expression's parameter x cannot redeclare 86 | * another local variable defined in an enclosing scope." 87 | */ 88 | Consumer myConsumer = (y) -> { 89 | 90 | // x is the arg value passed into the first level methodInFirstLevel(). 91 | System.out.println("x = " + x); // prints 10 92 | 93 | // y is the value passed into the accept() method called by the methodInFirstLevel() method. 94 | System.out.println("y = " + y); // prints 10 95 | 96 | // Lambda can access the x instance variable in first level nested class using 'this' 97 | System.out.println("this.x = " + this.x); // prints 2 98 | 99 | // Lambda can access the x intance variable in the outermost scope 100 | System.out.println("LambdaScoping.this.x = " + LambdaScoping.this.x); // prints 1 101 | }; 102 | 103 | // Call the lambda expression. The x arg beomes the the y arg in the lambda 104 | myConsumer.accept(x); // 15 // set this to 15 and y sysout will print 15 105 | } 106 | } 107 | 108 | /** 109 | * Runs the scoping test. 110 | * 111 | * @param args 112 | */ 113 | public static void main(String... args) 114 | { 115 | final LambdaScoping outerClass = new LambdaScoping(); 116 | final LambdaScoping.FirstLevel firstLevelClass = outerClass.new FirstLevel(); 117 | firstLevelClass.methodInFirstLevel(10); 118 | } 119 | } 120 | -------------------------------------------------------------------------------- /jdbl-core/src/test/resources/coverage/report_jacoco.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 91 | 92 | 93 | -------------------------------------------------------------------------------- /jdbl-core/src/main/java/se/kth/castor/jdbl/coverage/JCovReportReader.java: -------------------------------------------------------------------------------- 1 | package se.kth.castor.jdbl.coverage; 2 | 3 | import java.io.File; 4 | import java.io.IOException; 5 | import java.io.StringReader; 6 | import java.util.HashSet; 7 | 8 | import org.w3c.dom.Document; 9 | import org.w3c.dom.Node; 10 | import org.w3c.dom.NodeList; 11 | import org.xml.sax.InputSource; 12 | import org.xml.sax.SAXException; 13 | 14 | import javax.xml.parsers.DocumentBuilder; 15 | import javax.xml.parsers.DocumentBuilderFactory; 16 | import javax.xml.parsers.ParserConfigurationException; 17 | 18 | public class JCovReportReader 19 | { 20 | private UsageAnalysis usageAnalysis; 21 | private final DocumentBuilder dBuilder; 22 | 23 | public JCovReportReader() throws ParserConfigurationException 24 | { 25 | DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance(); 26 | 27 | dBuilder = dbFactory.newDocumentBuilder(); 28 | // Ignore the lack of DTD 29 | dBuilder.setEntityResolver((publicId, systemId) -> { 30 | if (systemId.contains(".dtd")) { 31 | return new InputSource(new StringReader("")); 32 | } else { 33 | return null; 34 | } 35 | }); 36 | } 37 | 38 | /** 39 | * Return a collection of used classes and used methods organized as following: 40 | * Map: class fullyQualifiedName -> Set< used method qualifier > if the class contains covered methods 41 | * method qualifier = methodSimpleName + descriptor 42 | * descriptor = (paramTypes;*)returnType 43 | * ex: method "contains(Ljava/lang/Object;)Z" is named contains and take an object as parameter and return a boolean 44 | */ 45 | public UsageAnalysis getUsedClassesAndMethods(File jcovXMLReport) throws IOException, SAXException 46 | { 47 | usageAnalysis = new UsageAnalysis(); 48 | Document doc = dBuilder.parse(jcovXMLReport); 49 | doc.getDocumentElement().normalize(); 50 | 51 | NodeList packages = doc.getElementsByTagName("package"); 52 | for (int i = 0; i < packages.getLength(); i++) { 53 | visitPackage(packages.item(i)); 54 | } 55 | 56 | // Remove all classes that do not contain any covered method 57 | usageAnalysis.removeUncoveredClasses(); 58 | 59 | return usageAnalysis; 60 | } 61 | 62 | private void visitPackage(Node p) 63 | { 64 | String packageName = p.getAttributes().getNamedItem("name").getNodeValue().replace(".", "/"); 65 | NodeList classes = p.getChildNodes(); 66 | for (int i = 0; i < classes.getLength(); i++) { 67 | Node n = classes.item(i); 68 | if (n.getNodeName().equals("class")) { 69 | visitClass(n, packageName); 70 | } 71 | } 72 | } 73 | 74 | private void visitClass(Node c, String packageName) 75 | { 76 | NodeList methods = c.getChildNodes(); 77 | 78 | String className = c.getAttributes().getNamedItem("name").getNodeValue(); 79 | usageAnalysis.addEntry(packageName + "/" + className, new HashSet<>()); 80 | for (int i = 0; i < methods.getLength(); i++) { 81 | Node n = methods.item(i); 82 | if (!n.getNodeName().equals("meth")) { 83 | continue; 84 | } 85 | visitMethod(n, packageName); 86 | } 87 | } 88 | 89 | private void visitMethod(Node m, String packageName) 90 | { 91 | if (!isCovered(m, "methenter")) { 92 | return; 93 | } 94 | String desc = m.getAttributes().getNamedItem("name").getNodeValue() + 95 | m.getAttributes().getNamedItem("vmsig").getNodeValue(); 96 | 97 | // we add the method only if it is covered 98 | String className = m.getParentNode().getAttributes().getNamedItem("name").getNodeValue(); 99 | usageAnalysis.methods(packageName + "/" + className).add(desc); 100 | } 101 | 102 | private boolean isCovered(Node m, String entity) 103 | { 104 | NodeList counters = m.getChildNodes(); 105 | 106 | if (counters.getLength() == 0) { 107 | Node nodeCounter = null; 108 | nodeCounter = m.getAttributes().getNamedItem("count"); 109 | if (nodeCounter == null) { 110 | return true; 111 | } else { 112 | return !nodeCounter.getNodeValue().equals("0"); 113 | } 114 | } else { 115 | 116 | for (int i = 0; i < counters.getLength(); i++) { 117 | Node n = counters.item(i); 118 | if (!n.getNodeName().equals("bl")) { 119 | continue; 120 | } 121 | 122 | NodeList blList = n.getChildNodes(); 123 | Node nodeCounter = null; 124 | for (int j = 0; j < blList.getLength(); ++j) { 125 | Node node = blList.item(j); 126 | if (node.getNodeName().equals(entity)) { 127 | nodeCounter = node.getAttributes().getNamedItem("count"); 128 | break; 129 | } 130 | } 131 | if (nodeCounter == null) { 132 | continue; 133 | } else { 134 | return !nodeCounter.getNodeValue().equals("0"); 135 | } 136 | } 137 | } 138 | return true; 139 | } 140 | } 141 | --------------------------------------------------------------------------------