Намиране на неизползвани зависимости на Gradle

1. Общ преглед

Понякога по време на разработката може да добавим повече зависимости, отколкото използваме.

В този бърз урок ще видим как да използваме приставката Gradle Nebula Lint за идентифициране и отстраняване на проблеми като тези.

2. Настройка и конфигуриране

Използваме мултимодулна настройка Gradle 5 в нашите примери.

Този плъгин работи само за базирани на Groovy файлове за изграждане .

Нека го конфигурираме в основния файл за изграждане на проекта:

plugins { id "nebula.lint" version "16.9.0" } description = "Gradle 5 root project" allprojects { apply plugin :"java" apply plugin :"nebula.lint" gradleLint { rules=['unused-dependency'] } group = "com.baeldung" version = "0.0.1" sourceCompatibility = "1.8" targetCompatibility = "1.8" repositories { jcenter() } }

Понастоящем можем да го конфигурираме само за компилации с множество проекти . Това означава, че не можем да го прилагаме отделно във всеки модул.

След това нека конфигурираме нашите модулни зависимости:

description = "Gradle Unused Dependencies example" dependencies { implementation('com.google.guava:guava:29.0-jre') testImplementation('junit:junit:4.12') }

Сега нека добавим прост основен клас в нашите модулни източници:

public class UnusedDependencies { public static void main(String[] args) { System.out.println("Hello world"); } }

Ще надградим върху това малко по-късно и ще видим как работи приставката.

3. Сценарии и доклади за откриване

Приставката търси изходните буркани, за да открие дали се използва зависимост или не.

Въпреки това, в зависимост от няколко условия, това може да ни даде различни резултати .

Ще разгледаме по-интересните случаи в следващите раздели.

3.1. Неизползвани зависимости

Сега, когато разполагаме с нашата настройка, нека видим основния случай на употреба. Интересуваме се от неизползвани зависимости.

Нека да стартираме задачата lintGradle :

$ ./gradlew lintGradle > Task :lintGradle FAILED # failure output omitted warning unused-dependency this dependency is unused and can be removed unused-dependencies/build.gradle:6 implementation('com.google.guava:guava:29.0-jre') ✖ 1 problem (0 errors, 1 warning) To apply fixes automatically, run fixGradleLint, review, and commit the changes. # some more failure output 

Да видим какво се случи. Имаме неизползвана зависимост ( гуава ) в нашата конфигурация compileClasspath .

Ако стартирате fixGradleLint задача като плъгин предполага, зависимостта се премахва автоматично от нашата build.gradle .

Нека вместо това използваме фиктивна логика с нашата зависимост:

public static void main(String[] args) { System.out.println("Hello world"); useGuava(); } private static void useGuava() { List list = ImmutableList.of("Baledung", "is", "cool"); System.out.println(list.stream().collect(Collectors.joining(" "))); }

Ако го повторим, не получаваме повече грешки:

$ ./gradlew lintGradle BUILD SUCCESSFUL in 559ms 3 actionable tasks: 1 executed, 2 up-to-date

3.2. Използване на преходни зависимости

Нека сега включим друга зависимост:

dependencies { implementation('com.google.guava:guava:29.0-jre') implementation('org.apache.httpcomponents:httpclient:4.5.12') testImplementation('junit:junit:4.12') }

Този път нека използваме нещо от преходна зависимост:

public static void main(String[] args) { System.out.println("Hello world"); useGuava(); useHttpCore(); } // other methods private static void useHttpCore() { SSLContextBuilder.create(); }

Нека да видим какво ще стане:

$ ./gradlew lintGradle > Task :lintGradle FAILED # failure output omitted warning unused-dependency one or more classes in org.apache.httpcomponents:httpcore:4.4.13 are required by your code directly (no auto-fix available) warning unused-dependency this dependency is unused and can be removed unused-dependencies/build.gradle:8 implementation('org.apache.httpcomponents:httpclient:4.5.12') ✖ 2 problems (0 errors, 2 warnings)

Получаваме две грешки. Първата грешка грубо казва, че трябва да се позоваваме директно на httpcore .

В SSLContextBuilder в нашата извадка е всъщност част от нея.

Втората грешка казва, че не използваме нищо от httpclient.

Ако използваме преходна зависимост, приставката ни казва да я направим директна .

Нека надникнем в нашето дърво на зависимостите:

$ ./gradlew unused-dependencies:dependencies --configuration compileClasspath > Task :unused-dependencies:dependencies ------------------------------------------------------------ Project :unused-dependencies - Gradle Unused Dependencies example ------------------------------------------------------------ compileClasspath - Compile classpath for source set 'main'. +--- com.google.guava:guava:29.0-jre | +--- com.google.guava:failureaccess:1.0.1 | +--- com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava | +--- com.google.code.findbugs:jsr305:3.0.2 | +--- org.checkerframework:checker-qual:2.11.1 | +--- com.google.errorprone:error_prone_annotations:2.3.4 | \--- com.google.j2objc:j2objc-annotations:1.3 \--- org.apache.httpcomponents:httpclient:4.5.12 +--- org.apache.httpcomponents:httpcore:4.4.13 +--- commons-logging:commons-logging:1.2 \--- commons-codec:commons-codec:1.11

В този случай можем да видим, че httpcore се въвежда от httpclient .

3.3. Използване на зависимости с отражение

Ами когато използваме размисъл?

Нека подобрим малко нашия пример:

public static void main(String[] args) { System.out.println("Hello world"); useGuava(); useHttpCore(); useHttpClientWithReflection(); } // other methods private static void useHttpClientWithReflection() { try { Class httpBuilder = Class.forName("org.apache.http.impl.client.HttpClientBuilder"); Method create = httpBuilder.getMethod("create", null); create.invoke(httpBuilder, null); } catch (Exception e) { e.printStackTrace(); } }

Сега нека повторим задачата Gradle:

$ ./gradlew lintGradle > Task :lintGradle FAILED # failure output omitted warning unused-dependency one or more classes in org.apache.httpcomponents:httpcore:4.4.13 are required by your code directly (no auto-fix available) warning unused-dependency this dependency is unused and can be removed unused-dependencies/build.gradle:9 implementation('org.apache.httpcomponents:httpclient:4.5.12') ✖ 2 problems (0 errors, 2 warnings) 

Какво стана? Използвахме HttpClientBuilder от нашата зависимост (httpclient), но все пак имаме грешки.

Ако използваме библиотека с отражение, приставката не открива нейното използване .

В резултат на това можем да видим същите две грешки.

Като цяло трябва да конфигурираме такива зависимости като runtimeOnly .

3.4. Генериране на отчети

За големите проекти броят на грешките, върнати в терминала, е труден за справяне.

Нека конфигурираме приставката, за да ни даде отчет вместо това:

allprojects { apply plugin :"java" apply plugin :"nebula.lint" gradleLint { rules=['unused-dependency'] reportFormat = 'text' } // other details omitted }

Нека да управляват generateGradleLintReport задача и да проверят нашата изграждане изход:

$ ./gradlew generateGradleLintReport # task output omitted $ cat unused-dependencies/build/reports/gradleLint/unused-dependencies.txt CodeNarc Report - Jun 20, 2020, 3:25:28 PM Summary: TotalFiles=1 FilesWithViolations=1 P1=0 P2=3 P3=0 File: /home/user/tutorials/gradle-5/unused-dependencies/build.gradle Violation: Rule=unused-dependency P=2 Line=null Msg=[one or more classes in org.apache.httpcomponents:httpcore:4.4.13 are required by your code directly] Violation: Rule=unused-dependency P=2 Line=9 Msg=[this dependency is unused and can be removed] Src=[implementation('org.apache.httpcomponents:httpclient:4.5.12')] Violation: Rule=unused-dependency P=2 Line=17 Msg=[this dependency is unused and can be removed] Src=[testImplementation('junit:junit:4.12')] [CodeNarc (//www.codenarc.org) v0.25.2] 

Сега той открива неизползвани зависимости от конфигурацията testCompileClasspath .

За съжаление това е непоследователно поведение на приставката. В резултат на това получаваме три грешки.

4. Заключение

В този урок видяхме как да намерим неизползвани зависимости при изграждането на Gradle.

Първо обяснихме общата настройка. След това проучихме съобщените грешки с различни зависимости и тяхното използване.

Накрая видяхме как да генерираме текстови отчети.

Както обикновено, можем да намерим пълните примерни кодове в GitHub.