Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

436 aspect j maven plugin #461

Open
wants to merge 13 commits into
base: develop
Choose a base branch
from
3 changes: 3 additions & 0 deletions mvvmfx-aspectj/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
.idea
mvvmfx-aspectj.iml
target
157 changes: 157 additions & 0 deletions mvvmfx-aspectj/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
# Architecture Checks with AspectJ

AspectJ can be used to check MVVM-Architecture errors.

These errors involve mostly on method calls or class-dependencies to unallowed layers within the MVVM pattern, like the View using Model objects or access to the _javafx.scene_ package in the ViewModel or the Model.

Since every project has different model packages we have built a plugin to ease aspect configurations for the mvvmFX framework.
These aspects will not change any logic on the project and are only used for architecture checks for the MVVM pattern with mvvmFX.

## Setting up Maven for mvvmFX architecture checks

- add dependency to UI-module or project

```xml
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.8.9</version>
</dependency>
```
- in the same file add the mvvmFX aspect creator plugin and the AspectJ compiler plugin

```xml
<plugins>
<plugin>
<groupId>de.saxsys</groupId>
<artifactId>mvvmfx-aspect-creator-plugin</artifactId>
<version>1.6.0-SNAPSHOT</version>
<configuration>
<modelPackages>
<package>com.example.dao</package>
<package>com.example.business</package>
<package>com.example.mypackage</package>
</modelPackages>
<modelClasses>
<class>com.example.myotherpackage.MyClass</class>
</modelClasses>
</configuration>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>aspectj-maven-plugin</artifactId>
<version>1.8</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
<complianceLevel>1.8</complianceLevel>
<verbose>true</verbose>
</configuration>
<executions>
<execution>
<goals>
<goal>compile</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
```

## create the aspects and compile the project
To create the aspects we have to configure it first. To do this we add the packages or the fully qualified name of the classes in the configuration of the plugin.
The View and ViewModel classes don't have to be configured.

After this we execute the plugin to create the aspects with "_mvn mvvmfx-aspect-creator:createaspects_".

Compile the project or UI-module with "_mvn clean install_" or "_mvn aspectj:compile_".

If there are some errors found the compiler will then throw error messages with the class, line of code and reason why there is an error.
If no errors were found, then good job!

## For Multi-Module Maven Projects
If the project has Multi-Modules, where the Layers(View, ViewModel and Model) are in different Modules then the above method won't fully work.
This is because half of the Aspects won't be applied on the modules because the modules are compiled separately.

To solve this issue we have to

First create a new module for our aspects on the parent module.
It is important to note the "_\<artifactId>_". For the purpose of this example the module name will be "_aspects_"
In this module we add two plugins to our pom:
```xml
<build>
<plugins>
<plugin>
<groupId>de.saxsys</groupId>
<artifactId>mvvmfx-aspect-creator-plugin</artifactId>
<configuration>
<modelPackages>
<package>com.example.dao</package>
<package>com.example.business</package>
<package>com.example.mypackage</package>
</modelPackages>
<modelClasses>
<class>com.example.mypackage.SomeClass</class>
</modelClasses>
</configuration>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>aspectj-maven-plugin</artifactId>
<version>1.9</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
<complianceLevel>1.8</complianceLevel>
<verbose>true</verbose>
<Xlint>ignore</Xlint>
</configuration>
<executions>
<execution>
<goals>
<goal>compile</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
```

We then create the aspects using the plugin with "_mvn mvvmfx-aspect-creator:createaspects_". This will create a folder aspect on src/main of the module.
We also have to compile this aspects with "_mvn aspectj:compile_" or "_mvn clean install_".
__NOTE: use this command while inside of the module if not the aspects will be created on the folder where the command was executed and you will have to move them to the aspects module__

After this we just have to add an aspectj plugin on every module that will apply our created aspects to each module.
The aspect library tag has to be directed to the module where the aspects where created

```xml
<build>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>aspectj-maven-plugin</artifactId>
<version>1.9</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
<complianceLevel>1.8</complianceLevel>
<verbose>true</verbose>
<aspectLibraries>
<aspectLibrary>
<groupId>com.example</groupId>
<artifactId>aspects</artifactId>
</aspectLibrary>
</aspectLibraries>
</configuration>
<executions>
<execution>
<goals>
<goal>compile</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
```
51 changes: 51 additions & 0 deletions mvvmfx-aspectj/aspect-creator-plugin/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
<?xml version="1.0" encoding="UTF-8"?>
<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">
<parent>
<artifactId>mvvmfx-aspectj</artifactId>
<groupId>de.saxsys</groupId>
<version>1.6.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>

<artifactId>mvvmfx-aspect-creator-plugin</artifactId>
<packaging>maven-plugin</packaging>
<name>MvvmFX Aspect creator</name>

<dependencies>
<dependency>
<groupId>org.apache.maven</groupId>
<artifactId>maven-plugin-api</artifactId>
<version>3.0</version>
</dependency>

<dependency>
<groupId>org.apache.maven.plugin-tools</groupId>
<artifactId>maven-plugin-annotations</artifactId>
<version>3.5</version>
<scope>provided</scope><!-- annotations are needed only to build the plugin -->
</dependency>

</dependencies>

<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.3</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-plugin-plugin</artifactId>
<version>3.3</version>
</plugin>
</plugins>
</build>

</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package de.saxsys.mvvmfx.aspectj.aspectcreator;

import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.logging.Log;
import org.apache.maven.plugins.annotations.Mojo;
import org.apache.maven.plugins.annotations.Parameter;

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

@Mojo(name = "createaspects")
public class AspectMakerMojo extends AbstractMojo{

/**
* Model Packages.
*/
@Parameter
private List<String> modelPackages = new ArrayList<>();

/**
* Model Classes.
*/
@Parameter
private List<String> modelClasses = new ArrayList<>();

public void execute() throws MojoExecutionException {
Log log = getLog();
log.info("Creating aspects");

modelPackages.forEach((String p) -> {
p = p.trim() + "..*";
Config.addToModel(p);
log.info("added as model: "+p);
});

modelClasses.forEach((String c) -> {
c = c.trim();
Config.addToModel(c);
log.info("added as model: "+c);

});

CodeGenerator codeGenerator = new CodeGenerator();
codeGenerator.createAspects();

log.info("Aspects created");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
package de.saxsys.mvvmfx.aspectj.aspectcreator;

import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Collections;

class CodeGenerator {

CodeGenerator() {
}

private Pointcut withinModelPointcut = new Pointcut("withinModel()", "within", Config.modelInterface);
private Pointcut withinViewModelPointcut = new Pointcut("withinViewModel()", "within", Config.viewModelInterface);
private Pointcut withinViewPointcut = new Pointcut("withinView()","within", Config.viewInterfaces);

void createAspects() {
Path aspectsPath = Paths.get("./src/main/aspect");
if (aspectsPath.toFile().exists()) {
deleteFiles(aspectsPath);
}
JarFileCopier.copyResourceDirectory();
createWithinMVVMAspect();
}

private void createWithinMVVMAspect() {
String aspect = "package de.saxsys.mvvmfx.aspectj.aspects; \n\n" +
"public abstract aspect " + "WithinMVVM" + " {\n\n" +
" public " + withinModelPointcut.toString() + "\n" +
" public " + withinViewPointcut.toString() + "\n" +
" public " + withinViewModelPointcut.toString() + "\n\n" +
" " + Declaration.declareParents(Config.modelInterface, Config.model) +
"\n}";

Path withinMVVMPath = Paths.get("./src/main/aspect/de/saxsys/mvvmfx/aspectj/aspects/WithinMVVM.aj");
byte data[] = aspect.getBytes();
try {
if (!withinMVVMPath.toFile().exists()) {
Files.createFile(withinMVVMPath);
Files.write(withinMVVMPath, data);
}
} catch (IOException e) {
e.printStackTrace();
}
}

private void deleteFiles(Path dir){
try {

Files.walk(dir)
.map(Path::toFile)
.sorted(Collections.reverseOrder())
.forEach(File::delete);

} catch (IOException e) {
e.printStackTrace();
}

}


}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package de.saxsys.mvvmfx.aspectj.aspectcreator;

import java.util.ArrayList;

final class Config {

static ArrayList<String> model = new ArrayList<>();
static String modelInterface = "Model+";
static String viewInterfaces = "de.saxsys.mvvmfx.JavaView+ || de.saxsys.mvvmfx.FxmlView+";
static String viewModelInterface = "de.saxsys.mvvmfx.ViewModel+";


static void addToModel(String packageName){
model.add(packageName);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package de.saxsys.mvvmfx.aspectj.aspectcreator;

import java.util.ArrayList;

class Declaration {

static String declareParents(String parentName, ArrayList<String> signatures) {
if(signatures.isEmpty()) return "";

StringBuilder declaration = new StringBuilder("declare parents: ");

for(int i = 0; i<signatures.size()-1; i++){
declaration.append(signatures.get(i)).append(" || ");
}

//last item
declaration.append(signatures.get(signatures.size()-1));

declaration.append(" implements ").append(parentName).append(";");



return declaration.toString();
}
}
Loading