2017-01-12 4 views
1

Я пытаюсь расширить третий код lib с новыми возможностями.Можно ли сплести некоторые классы из банки, исключая остальные классы?

И так как мне нужно только придать некоторый код вокруг одного метода из одного класса, я понял, что я могу либо:

  1. вил проект и применить свои изменения (seems sloppy, and will definitely require lots of work whenever I try to upgrade to a newer version of the lib, not to mention licensing nightmare)
  2. Использование [AOP] для перехватывать, что один метод из этого одного класса внутри огромного кувшина (seems cleaner) и вводят свои дополнительные испытания

в случае, если любой из вас хочет знать, что один класс не является пружинный боб и глубоко используется в коде , поэтому я не могу просто расширить i t и переопределить/обернуть этот метод легко, для этого потребуется, по меньшей мере, несколько дополнительных слоев расширения & переопределить/обернуть. Итак, AspectJ & AOP кажется лучшим способом.

Мне удалось установить мой проект с помощью какого-то плагина, чтобы вызвать ajc и сплести код с моей нужной банкой в ​​параметре -inpath. И единственная проблема заключается в том, что ajc, кажется, переплетает все (или, по крайней мере, дублирует его);

Так что мне нужно в основном попросить AJC просто выманить этот класс из этой банки, а не целую банку!

+0

Мне кажется, что это простой шаг до и после обработки в вашей сборке. Плету свою зависимость от jar, результатом будет куча двоичных классов. Возьмите модифицированный класс, который вам нужен, возьмите другие классы из оригинальной банки без изменений и упакуйте их в банку. –

+0

@ NándorElődFekete мой проект представляет собой пакет OSGI, и когда 'ajc' создает сплетенные классы, они автоматически упаковываются вместе в комплекте. Но некоторые из 3-х партийных классов полагаются на другие сторонние библиотеки (необязательные библиотеки), которые используются в моем случае никогда не достигаемым кодом, но приводят к тому, что контейнер OSJI устанавливает пакет для отсутствующих зависимостей. –

+0

Я не вижу OSGI что-либо в этом случае. Если, конечно, вы не используете безголовую среду сборки и полагаетесь вместо этого на Eclipse IDE для создания своего проекта. –

ответ

3

Как вы заметили, компилятор AspectJ всегда выводит все файлы, найденные в зависимостях weave (in-JAR), независимо от того, изменены они или нет. Это поведение не может быть изменено с помощью командной строки AFAIK. Поэтому вам нужно позаботиться о том, чтобы упаковать ваши JAR самостоятельно.

Вот пример проекта вкл. Maven POM показывает вам, как это сделать. Я выбрал довольно глупый пример с участием Apache Commons Кодек:

Пример приложения:

Приложение base64 кодирует текст, расшифровывает его снова и печатает оба текста в консоли.

package de.scrum_master.app; 

import org.apache.commons.codec.binary.Base64; 

public class Application { 
    public static void main(String[] args) throws Exception { 
     String originalText = "Hello world!"; 
     System.out.println(originalText); 
     byte[] encodedBytes = Base64.encodeBase64(originalText.getBytes()); 
     String decodedText = new String(Base64.decodeBase64(encodedBytes)); 
     System.out.println(decodedText); 
    } 
} 

Обычно выход выглядит так:

Hello world! 
Hello world! 

Никаких сюрпризов здесь. Но теперь мы определяем аспект, который манипулирует результаты, возвращенные из библиотеки третьей стороны, заменяя каждый символ «O» (о) на «0» (ноль):

package de.scrum_master.aspect; 

import org.apache.commons.codec.binary.Base64; 

public aspect Base64Manipulator { 
    byte[] around() : execution(byte[] Base64.decodeBase64(byte[])) { 
     System.out.println(thisJoinPoint); 
     byte[] result = proceed(); 
     for (int i = 0; i < result.length; i++) { 
      if (result[i] == 'o') 
       result[i] = '0'; 
     } 
     return result; 
    } 
} 

Кстати, если бы вы просто использовать call() вместо execution() здесь не нужно было бы переплетаться в сторонний код. Но в любом случае, вы просили об этом, поэтому я покажу вам, как это сделать.

Maven POM:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 
    <modelVersion>4.0.0</modelVersion> 

    <groupId>de.scrum-master.stackoverflow</groupId> 
    <artifactId>aspectj-weave-single-3rd-party-class</artifactId> 
    <version>1.0-SNAPSHOT</version> 

    <properties> 
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> 
    <java.source-target.version>1.8</java.source-target.version> 
    <aspectj.version>1.8.10</aspectj.version> 
    <main-class>de.scrum_master.app.Application</main-class> 
    </properties> 

    <build> 

    <pluginManagement> 
     <plugins> 

     <plugin> 
      <groupId>org.apache.maven.plugins</groupId> 
      <artifactId>maven-compiler-plugin</artifactId> 
      <version>3.6.0</version> 
      <configuration> 
      <source>${java.source-target.version}</source> 
      <target>${java.source-target.version}</target> 
      <!-- IMPORTANT --> 
      <useIncrementalCompilation>false</useIncrementalCompilation> 
      </configuration> 
     </plugin> 

     <plugin> 
      <groupId>org.codehaus.mojo</groupId> 
      <artifactId>aspectj-maven-plugin</artifactId> 
      <version>1.9</version> 
      <configuration> 
      <!--<showWeaveInfo>true</showWeaveInfo>--> 
      <source>${java.source-target.version}</source> 
      <target>${java.source-target.version}</target> 
      <Xlint>ignore</Xlint> 
      <complianceLevel>${java.source-target.version}</complianceLevel> 
      <encoding>${project.build.sourceEncoding}</encoding> 
      <!--<verbose>true</verbose>--> 
      <!--<warn>constructorName,packageDefaultMethod,deprecation,maskedCatchBlocks,unusedLocals,unusedArguments,unusedImport</warn>--> 
      <weaveDependencies> 
       <dependency> 
       <groupId>commons-codec</groupId> 
       <artifactId>commons-codec</artifactId> 
       </dependency> 
      </weaveDependencies> 
      </configuration> 
      <executions> 
      <execution> 
       <!-- IMPORTANT --> 
       <phase>process-sources</phase> 
       <goals> 
       <goal>compile</goal> 
       <goal>test-compile</goal> 
       </goals> 
      </execution> 
      </executions> 
      <dependencies> 
      <dependency> 
       <groupId>org.aspectj</groupId> 
       <artifactId>aspectjtools</artifactId> 
       <version>${aspectj.version}</version> 
      </dependency> 
      <dependency> 
       <groupId>org.aspectj</groupId> 
       <artifactId>aspectjweaver</artifactId> 
       <version>${aspectj.version}</version> 
      </dependency> 
      </dependencies> 
     </plugin> 

     <plugin> 
      <groupId>org.codehaus.mojo</groupId> 
      <artifactId>exec-maven-plugin</artifactId> 
      <version>1.5.0</version> 
      <configuration> 
      <mainClass>${main-class}</mainClass> 
      </configuration> 
     </plugin> 

     </plugins> 
    </pluginManagement> 

    <plugins> 
     <plugin> 
     <groupId>org.codehaus.mojo</groupId> 
     <artifactId>aspectj-maven-plugin</artifactId> 
     </plugin> 
     <plugin> 
     <artifactId>maven-clean-plugin</artifactId> 
     <version>2.5</version> 
     <executions> 
      <execution> 
      <id>remove-unwoven</id> 
      <!-- Phase 'process-classes' is in between 'compile' and 'package' --> 
      <phase>process-classes</phase> 
      <goals> 
       <goal>clean</goal> 
      </goals> 
      <configuration> 
       <!-- No full clean, only what is specified in 'filesets' --> 
       <excludeDefaultDirectories>true</excludeDefaultDirectories> 
       <filesets> 
       <fileset> 
        <directory>${project.build.outputDirectory}</directory> 
        <includes> 
        <include>org/apache/commons/codec/**</include> 
        <include>META-INF/**</include> 
        </includes> 
        <excludes> 
        <exclude>**/Base64.class</exclude> 
        </excludes> 
       </fileset> 
       </filesets> 
       <!-- Set to true if you want to see what exactly gets deleted --> 
       <verbose>false</verbose> 
      </configuration> 
      </execution> 
     </executions> 
     </plugin> 
     <plugin> 
     <groupId>org.codehaus.mojo</groupId> 
     <artifactId>exec-maven-plugin</artifactId> 
     </plugin> 
    </plugins> 

    </build> 

    <dependencyManagement> 
    <dependencies> 
     <dependency> 
     <groupId>org.aspectj</groupId> 
     <artifactId>aspectjrt</artifactId> 
     <version>${aspectj.version}</version> 
     <scope>runtime</scope> 
     </dependency> 
     <dependency> 
     <groupId>commons-codec</groupId> 
     <artifactId>commons-codec</artifactId> 
     <version>1.10</version> 
     </dependency> 
    </dependencies> 
    </dependencyManagement> 

    <dependencies> 
    <dependency> 
     <groupId>org.aspectj</groupId> 
     <artifactId>aspectjrt</artifactId> 
    </dependency> 
    <dependency> 
     <groupId>commons-codec</groupId> 
     <artifactId>commons-codec</artifactId> 
    </dependency> 
    </dependencies> 

    <organization> 
    <name>Scrum-Master.de - Agile Project Management</name> 
    <url>http://scrum-master.de</url> 
    </organization> 
</project> 

Как вы можете видеть, я использую <weaveDependencies> в плагине AspectJ Maven (что переводится -inpath для компилятора AspectJ) в сочетании со специальным исполнением плагин Maven Clean который удаляет все ненужные классы и каталог META-INF из исходного JAR.

Если вы запускаете mvn clean package exec:java вы видите:

[INFO] ------------------------------------------------------------------------ 
[INFO] Building aspectj-weave-single-3rd-party-class 1.0-SNAPSHOT 
[INFO] ------------------------------------------------------------------------ 
(...) 
[INFO] --- aspectj-maven-plugin:1.9:compile (default) @ aspectj-weave-single-3rd-party-class --- 
[INFO] Showing AJC message detail for messages of types: [error, warning, fail] 
(...) 
[INFO] --- maven-clean-plugin:2.5:clean (remove-unwoven) @ aspectj-weave-single-3rd-party-class --- 
[INFO] Deleting C:\Users\Alexander\Documents\java-src\SO_AJ_MavenWeaveSingle3rdPartyClass\target\classes (includes = [org/apache/commons/codec/**, META-INF/**], excludes = [**/Base64.class]) 
(...) 
[INFO] --- maven-jar-plugin:2.4:jar (default-jar) @ aspectj-weave-single-3rd-party-class --- 
[INFO] Building jar: C:\Users\Alexander\Documents\java-src\SO_AJ_MavenWeaveSingle3rdPartyClass\target\aspectj-weave-single-3rd-party-class-1.0-SNAPSHOT.jar 
[INFO] 
[INFO] --- exec-maven-plugin:1.5.0:java (default-cli) @ aspectj-weave-single-3rd-party-class --- 
Hello world! 
execution(byte[] org.apache.commons.codec.binary.Base64.decodeBase64(byte[])) 
Hell0 w0rld! 
[INFO] ------------------------------------------------------------------------ 
[INFO] BUILD SUCCESS 
[INFO] ------------------------------------------------------------------------ 

И это то, что мой target/classes каталог выглядит после сборки:

Directory 'target/classes'

Как вы можете видеть, есть только один Файл класса Apache Commons, который находится в созданном JAR.

+0

Прежде всего, спасибо за усилия! Ваш ответ показывает, что вы определенно вложили некоторые усилия. Но я закончил тем, что отказался от этого подхода и переписал пару слоев, чтобы добиться желаемого поведения. Несмотря на то, что я использую gradle для управления моими зависимостями и сборки, я придумал решение, подобное вашему, только чтобы понять позже, что наличие класса этого пакета внутри моего пакета не позволяет контейнеру OSGI импортировать остальную часть классы из этого пакета из исходной библиотеки ... –

+0

Поскольку мой пакет является аддоном для решения ECM и должен быть подключен к нескольким версиям этого решения, я подумал, что было бы настоящей болью в прикладе, чтобы подготовить тканые зависимости для каждого и каждая версия хост-программного обеспечения ... и поддерживаем отдельный проект для этого. –

+0

Но, как я уже сказал, ваш ответ показывает много усилий и определенно будет работать, если бы у меня не было всех осложнений OSGi, поэтому голосование и оценка в качестве правильного ответа заслуживают в этом случае! –

Смежные вопросы