Skip to content

Commit

Permalink
feat: add maven plugin flags to skip abstract types (#478)
Browse files Browse the repository at this point in the history
  • Loading branch information
CarstenWickner authored Sep 27, 2024
1 parent cdf5aff commit c695f40
Show file tree
Hide file tree
Showing 9 changed files with 145 additions and 8 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
#### Fixed
- avoid exception in subtype resolution, when targeting void method

### `jsonschema-maven-plugin`
### Added
- support `<skipAbstractTypes>` flag to exclude abstract types (not interfaces)
- support `<skipInterfaces>` flag to exclude interface types

## [4.36.0] - 2024-07-20
### `jsonschema-generator`
#### Added
Expand Down
10 changes: 10 additions & 0 deletions jsonschema-maven-plugin/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,16 @@ The content of each of these elements can be either:
</configuration>
```

Additionally, you can omit the generation for abstract classes and/or interfaces by setting the respective `<skipAbstractTypes>` or `<skipInterfaces>`
flags to `true` (by default, they are `false`).
```xml
<configuration>
<packageNames>com/myOrg/myApp/package/**</packageNames>
<skipAbstractTypes>true</skipAbstractTypes>
<skipInterfaces>true</skipInterfaces>
</configuration>
```

#### Based on Annotations (`<annotations>`)

Alternatively classes can be selected based on annotations using the `<annotations>` element. Then
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
import java.io.PrintWriter;
import java.lang.reflect.Array;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Modifier;
import java.net.URL;
import java.net.URLClassLoader;
import java.nio.charset.StandardCharsets;
Expand Down Expand Up @@ -101,6 +102,22 @@ public class SchemaGeneratorMojo extends AbstractMojo {
@Parameter(property = "annotations")
private List<AnnotationParameter> annotations = new ArrayList<>();

/**
* Flag indicating whether abstract classes should be ignored, even if they are matching the classname and/or package pattern.
*
* @since 4.37.0
*/
@Parameter(property = "skipAbstractTypes", defaultValue = "false")
private boolean skipAbstractTypes;

/**
* Flag indicating whether interfaces should be ignored, even if they are matching the classname and/or package pattern.
*
* @since 4.37.0
*/
@Parameter(property = "skipInterfaces", defaultValue = "false")
private boolean skipInterfaces;

/**
* The classpath to look for classes to generate schema files.
*/
Expand Down Expand Up @@ -212,9 +229,7 @@ private void generateSchema(String classOrPackageName, boolean targetPackage) th
if (potentialTarget.isAlreadyGenerated()) {
this.getLog().info("- Skipping already generated " + potentialTarget.getFullClassName());
} else {
// Load the class for which the schema will be generated
Class<?> schemaClass = this.loadClass(potentialTarget.getFullClassName());
this.generateSchema(schemaClass);
this.generateSchema(potentialTarget);
potentialTarget.setAlreadyGenerated();
}
}
Expand All @@ -223,6 +238,25 @@ private void generateSchema(String classOrPackageName, boolean targetPackage) th
}
}

/**
* Generate the JSON schema for the indicated type matching a class name or package pattern. Considering further config flags potentially skipping
* the schema file generation.
*
* @param potentialTarget class to produce JSON schema file for
* @throws MojoExecutionException In case of problems
*/
private void generateSchema(PotentialSchemaClass potentialTarget) throws MojoExecutionException {
// Load the class for which the schema will be generated
Class<?> schemaClass = this.loadClass(potentialTarget.getFullClassName());
if (this.skipInterfaces && schemaClass.isInterface()) {
this.getLog().info("- Skipping interface " + potentialTarget.getFullClassName());
} else if (this.skipAbstractTypes && this.isAbstractClass(schemaClass)) {
this.getLog().info("- Skipping abstract type " + potentialTarget.getFullClassName());
} else {
this.generateSchema(schemaClass);
}
}

/**
* Generate the JSON schema for the given className.
*
Expand Down Expand Up @@ -565,4 +599,14 @@ private void writeToFile(JsonNode jsonSchema, File file) throws MojoExecutionExc
throw new MojoExecutionException("Error: Can not write to file " + file, e);
}
}

/**
* Check whether a given class is deemed abstract but not an interface.
*
* @param targetClass type to check
* @return whether the indicated type represents an abstract non-interface class
*/
private boolean isAbstractClass(Class<?> targetClass) {
return Modifier.isAbstract(targetClass.getModifiers()) && !targetClass.isInterface();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -158,13 +158,14 @@ public void testTwoClasses() throws Exception {
/**
* Unit test to test the generation of schemas for multiple classes
*/
@Test
public void testPackageName() throws Exception {
@ParameterizedTest
@ValueSource(strings = { "WithoutAbstracts", "WithoutInterfaces" })
public void testPackageName(String scenario) throws Exception {
File testCaseLocation = new File("src/test/resources/reference-test-cases");
File generationLocation = new File("target/generated-test-sources/PackageName");
File generationLocation = new File("target/generated-test-sources/PackageName" + scenario);

// Execute the pom
executePom(new File("src/test/resources/reference-test-cases/PackageName-pom.xml"));
executePom(new File("src/test/resources/reference-test-cases/PackageName" + scenario + "-pom.xml"));

// Validate that the schema files are created.
File resultFileA = new File(generationLocation,"TestClassA-schema.json");
Expand All @@ -179,6 +180,11 @@ public void testPackageName() throws Exception {
Assertions.assertTrue(resultFileC.exists());
resultFileC.deleteOnExit();

File resultFileAbstract = new File(generationLocation,"AbstractTestClass-schema.json");
Assertions.assertNotEquals("WithoutAbstracts".equals(scenario), resultFileAbstract.exists());
File resultFileInterface = new File(generationLocation,"TestInterface-schema.json");
Assertions.assertNotEquals("WithoutInterfaces".equals(scenario), resultFileInterface.exists());

// Validate that they are the same as the reference
File referenceFileA = new File(testCaseLocation, "TestClassA-reference.json");
Assertions.assertTrue(referenceFileA.exists());
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
/*
* Copyright 2024 VicTools.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.github.victools.jsonschema.plugin.maven.testpackage;

public abstract class AbstractTestClass {

public abstract int getInteger();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
/*
* Copyright 2024 VicTools.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.github.victools.jsonschema.plugin.maven.testpackage;

public interface TestInterface {

String getValue();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<project>
<build>
<plugins>
<plugin>
<groupId>com.github.victools</groupId>
<artifactId>jsonschema-maven-plugin</artifactId>
<configuration>
<packageNames>com.github.victools.jsonschema.plugin.maven.testpackage</packageNames>
<schemaFilePath>target/generated-test-sources/PackageNameWithoutAbstracts</schemaFilePath>
<excludeClassNames>com.github.victools.jsonschema.plugin.maven.testpackage.TestClassB</excludeClassNames>
<skipAbstractTypes>true</skipAbstractTypes>
</configuration>
</plugin>
</plugins>
</build>
</project>
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,9 @@
<artifactId>jsonschema-maven-plugin</artifactId>
<configuration>
<packageNames>com.github.victools.jsonschema.plugin.maven.testpackage</packageNames>
<schemaFilePath>target/generated-test-sources/PackageName</schemaFilePath>
<schemaFilePath>target/generated-test-sources/PackageNameWithoutInterfaces</schemaFilePath>
<excludeClassNames>com.github.victools.jsonschema.plugin.maven.testpackage.TestClassB</excludeClassNames>
<skipInterfaces>true</skipInterfaces>
</configuration>
</plugin>
</plugins>
Expand Down
11 changes: 11 additions & 0 deletions slate-docs/source/includes/_maven-plugin.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ There are a number of basic configuration options as well as the possibility to
<annotations>
<annotation>com.myOrg.MySchemaAnnotation</annotation>
</annotations>
<skipAbstractTypes>true</skipAbstractTypes>
<skipInterfaces>true</skipInterfaces>
<classpath>PROJECT_ONLY</classpath>
<failIfNoClassesMatch>false</failIfNoClassesMatch>
</configuration>
Expand Down Expand Up @@ -83,6 +85,15 @@ For example, the given configuration will create a `MyClass.schema` file.
To store the generated schema files in the same directory structure as the originating classes, the following can be used `<schemaFileName>{1}/{0}-schema.json</schemaFileName>`.
The default `<schemaFileName>` is `{0}-schema.json`.

Additionally, you can omit the generation for abstract classes and/or interfaces by setting the respective `<skipAbstractTypes>` or `<skipInterfaces>` flags to `true` (by default, they are `false`).
```xml
<configuration>
<packageNames>com/myOrg/myApp/package/**</packageNames>
<skipAbstractTypes>true</skipAbstractTypes>
<skipInterfaces>true</skipInterfaces>
</configuration>
```

### Selecting Options

```xml
Expand Down

0 comments on commit c695f40

Please sign in to comment.