Skip to content

Commit

Permalink
Merge branch 'master' into 4460
Browse files Browse the repository at this point in the history
  • Loading branch information
shawkins committed Sep 30, 2022
2 parents 19ba5ec + 1c0fe21 commit ebe482c
Show file tree
Hide file tree
Showing 21 changed files with 203 additions and 40 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
* Fix #3733: The authentication command from the .kube/config won't be discarded if no arguments are specified
* Fix #4441: corrected patch base handling for the patch methods available from a Resource - resource(item).patch() will be evaluated as resource(latest).patch(item). Also undeprecated patch(item), which is consistent with leaving patch(context, item) undeprecated as well. For consistency with the other operations (such as edit), patch(item) will use the context item as the base when available, or the server side item when not. This means that patch(item) is only the same as resource(item).patch() when the patch(item) is called when the context item is missing or is the same as the latest.
* Fix #4460: removing split packages. Converting Default clients into adapters rather than real instances.
* Fix #4442: TokenRefreshInterceptor doesn't overwrite existing OAuth token with empty string

#### Improvements
* Fix #4348: Introduce specific annotations for the generators
Expand All @@ -25,6 +26,7 @@

#### New Features
* Fix #4398: add annotation @PreserveUnknownFields for marking generated field have `x-kubernetes-preserve-unknown-fields: true` defined
* Fix #4351: add `javax.annotation.processing.Generated` to classes generated with the `java-generator`

#### _**Note**_: Breaking changes in the API
* Fix #4350: SchemaSwap's fieldName parameter now expects a field name only, not a method or a constructor.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,23 +29,25 @@
import io.sundr.model.TypeDef;
import io.sundr.model.repo.DefinitionRepository;

import java.io.IOException;
import java.io.OutputStream;
import java.lang.annotation.Annotation;
import java.net.URI;
import java.util.Locale;
import java.util.Optional;
import java.util.Set;

import javax.annotation.processing.*;
import javax.lang.model.element.Element;
import javax.lang.model.element.Name;
import javax.lang.model.element.TypeElement;
import javax.tools.Diagnostic;
import javax.tools.FileObject;
import javax.tools.StandardLocation;
import java.io.IOException;
import java.io.OutputStream;
import java.net.URI;
import java.util.Locale;
import java.util.Optional;
import java.util.Set;

@SupportedAnnotationTypes({"io.fabric8.kubernetes.model.annotation.Version"})
@SupportedAnnotationTypes({ "io.fabric8.kubernetes.model.annotation.Version" })
public class CustomResourceAnnotationProcessor extends AbstractProcessor {

private final CRDGenerator generator = new CRDGenerator();

public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
Expand All @@ -54,7 +56,8 @@ public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment
final CRDGenerationInfo allCRDs = generator.withOutput(new FileObjectCRDOutput(processingEnv)).detailedGenerate();
allCRDs.getCRDDetailsPerNameAndVersion().forEach((crdName, versionToInfo) -> {
messager.printMessage(Diagnostic.Kind.NOTE, "Generating CRD " + crdName + ":\n");
versionToInfo.forEach((version, info) -> messager.printMessage(Diagnostic.Kind.NOTE, " - " + version + " -> " + info.getFilePath()));
versionToInfo.forEach(
(version, info) -> messager.printMessage(Diagnostic.Kind.NOTE, " - " + version + " -> " + info.getFilePath()));
});
return true;
}
Expand All @@ -66,18 +69,27 @@ public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment
for (TypeElement annotation : annotations) {
for (Element element : roundEnv.getElementsAnnotatedWith(annotation)) {
if (element instanceof TypeElement) {
try {
// The annotation is loaded with reflection for compatibility with Java 8
Class<Annotation> generatedAnnotation = (Class<Annotation>) Class.forName("javax.annotation.processing.Generated");
if (element.getAnnotationsByType(generatedAnnotation).length > 0) {
continue;
}
} catch (ClassNotFoundException e) {
// ignore
}
generator.customResources(toCustomResourceInfo((TypeElement) element));
}
}
}

return false;
}

private CustomResourceInfo toCustomResourceInfo(TypeElement customResource) {
TypeDef definition = Adapters.adaptType(customResource, AptContext.getContext());
definition = Types.unshallow(definition);

if (CustomResourceInfo.DESCRIBE_TYPE_DEFS) {
Types.output(definition);
}
Expand All @@ -86,37 +98,38 @@ private CustomResourceInfo toCustomResourceInfo(TypeElement customResource) {
SpecAndStatus specAndStatus = Types.resolveSpecAndStatusTypes(definition);
if (specAndStatus.isUnreliable()) {
System.out.println("Cannot reliably determine status types for " + crClassName
+ " because it isn't parameterized with only spec and status types. Status replicas detection will be deactivated.");
+ " because it isn't parameterized with only spec and status types. Status replicas detection will be deactivated.");
}

final String group = customResource.getAnnotation(Group.class).value();
final String version = customResource.getAnnotation(Version.class).value();

final String kind = Optional.ofNullable(customResource.getAnnotation(Kind.class))
.map(Kind::value)
.orElse(customResource.getSimpleName().toString());
.map(Kind::value)
.orElse(customResource.getSimpleName().toString());

final String singular = Optional.ofNullable(customResource.getAnnotation(Singular.class))
.map(Singular::value)
.orElse(kind.toLowerCase(Locale.ROOT));
.map(Singular::value)
.orElse(kind.toLowerCase(Locale.ROOT));

final String plural = Optional.ofNullable(customResource.getAnnotation(Plural.class))
.map(Plural::value)
.map(s -> s.toLowerCase(Locale.ROOT))
.orElse(Pluralize.toPlural(singular));
.map(Plural::value)
.map(s -> s.toLowerCase(Locale.ROOT))
.orElse(Pluralize.toPlural(singular));

final String[] shortNames = Optional
.ofNullable(customResource.getAnnotation(ShortNames.class))
.map(ShortNames::value)
.orElse(new String[]{});
.ofNullable(customResource.getAnnotation(ShortNames.class))
.map(ShortNames::value)
.orElse(new String[] {});

final boolean storage = customResource.getAnnotation(Version.class).storage();
final boolean served = customResource.getAnnotation(Version.class).served();

final Scope scope = Types.isNamespaced(definition) ? Scope.NAMESPACED : Scope.CLUSTER;

return new CustomResourceInfo(group, version, kind, singular, plural, shortNames, storage, served, scope, definition, crClassName.toString(),
specAndStatus.getSpecClassName(), specAndStatus.getStatusClassName());
return new CustomResourceInfo(group, version, kind, singular, plural, shortNames, storage, served, scope, definition,
crClassName.toString(),
specAndStatus.getSpecClassName(), specAndStatus.getStatusClassName());
}

private static class FileObjectOutputStream extends OutputStream {
Expand Down Expand Up @@ -170,8 +183,8 @@ public FileObjectCRDOutput(ProcessingEnvironment processingEnv) {
@Override
protected FileObjectOutputStream createStreamFor(String crdName) throws IOException {
return new FileObjectOutputStream(
processingEnv.getFiler().createResource(StandardLocation.CLASS_OUTPUT, "",
"META-INF/fabric8/" + crdName + ".yml"));
processingEnv.getFiler().createResource(StandardLocation.CLASS_OUTPUT, "",
"META-INF/fabric8/" + crdName + ".yml"));
}

@Override
Expand All @@ -180,4 +193,3 @@ public URI crdURI(String crdName) {
}
}
}

Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,10 @@ public class GenerateJavaSources implements Runnable {
"--code-structure" }, description = "Generate classes using a specific layout", required = false, hidden = true)
String codeStructure = null;

@Option(names = { "-skip-generated-annotations",
"--skip-generated-annotations" }, description = "Add extra lombok and sundrio annotation to the generated classes", required = false, hidden = true)
Boolean skipGeneratedAnnotations = null;

@Override
public void run() {
final Config.Prefix pSt = (prefixStrategy != null) ? Config.Prefix.valueOf(prefixStrategy) : null;
Expand All @@ -66,7 +70,8 @@ public void run() {
sSt,
alwaysPreserveUnkownFields,
addExtraAnnotations,
structure);
structure,
!skipGeneratedAnnotations);
final CRGeneratorRunner runner = new CRGeneratorRunner(config);
runner.run(source, target);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,13 +39,15 @@ public enum Suffix {
private static final boolean DEFAULT_ALWAYS_PRESERVE_FIELDS = false;
private static final boolean DEFAULT_ADD_EXTRA_ANNOTATIONS = false;
private static final CodeStructure DEFAULT_CODE_STRUCTURE = CodeStructure.PACKAGE_NESTED;
private static final boolean DEFAULT_ADD_GENERATED_ANNOTATIONS = true;

private Boolean uppercaseEnums = DEFAULT_UPPERCASE_ENUM;
private Prefix prefixStrategy = DEFAULT_PREFIX_STRATEGY;
private Suffix suffixStrategy = DEFAULT_SUFFIX_STRATEGY;
private Boolean alwaysPreserveUnknownFields = DEFAULT_ALWAYS_PRESERVE_FIELDS;
private Boolean objectExtraAnnotations = DEFAULT_ADD_EXTRA_ANNOTATIONS;
private CodeStructure structure = DEFAULT_CODE_STRUCTURE;
private Boolean generatedAnnotations = DEFAULT_ADD_GENERATED_ANNOTATIONS;

public Config() {
}
Expand All @@ -56,7 +58,8 @@ public Config(
Suffix suffixStrategy,
Boolean alwaysPreserveUnknownFields,
Boolean objectExtraAnnotations,
CodeStructure structure) {
CodeStructure structure,
Boolean generatedAnnotations) {
if (uppercaseEnums != null) {
this.uppercaseEnums = uppercaseEnums;
}
Expand All @@ -75,6 +78,9 @@ public Config(
if (structure != null) {
this.structure = structure;
}
if (generatedAnnotations != null) {
this.generatedAnnotations = generatedAnnotations;
}
}

public boolean isUppercaseEnums() {
Expand Down Expand Up @@ -104,4 +110,10 @@ public boolean isObjectExtraAnnotations() {
public CodeStructure getCodeStructure() {
return (structure == null) ? DEFAULT_CODE_STRUCTURE : structure;
}

public boolean isGeneratedAnnotations() {
return (generatedAnnotations == null)
? DEFAULT_ADD_GENERATED_ANNOTATIONS
: generatedAnnotations;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@
package io.fabric8.java.generator.nodes;

import com.fasterxml.jackson.databind.JsonNode;
import com.github.javaparser.ast.expr.AnnotationExpr;
import com.github.javaparser.ast.expr.Name;
import com.github.javaparser.ast.expr.SingleMemberAnnotationExpr;
import com.github.javaparser.ast.expr.StringLiteralExpr;
import io.fabric8.java.generator.Config;
import io.fabric8.java.generator.exceptions.JavaGeneratorException;
import io.fabric8.kubernetes.api.model.apiextensions.v1.JSONSchemaProps;
Expand All @@ -39,6 +43,10 @@ public abstract class AbstractJSONSchema2Pojo {
static final String OBJECT_CRD_TYPE = "object";
static final String ARRAY_CRD_TYPE = "array";

public static final AnnotationExpr GENERATED_ANNOTATION = new SingleMemberAnnotationExpr(
new Name("javax.annotation.processing.Generated"),
new StringLiteralExpr("io.fabric8.java.generator.CRGeneratorRunner"));

protected final String description;
protected final Config config;
protected final boolean isNullable;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,9 @@ public GeneratorResult generateJava() {
clz.addExtendedType(crType);
clz.addImplementedType("io.fabric8.kubernetes.api.model.Namespaced");

if (config.isGeneratedAnnotations()) {
clz.addAnnotation(GENERATED_ANNOTATION);
}
if (config.isObjectExtraAnnotations()) {
addExtraAnnotations(clz);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,9 @@ public GeneratorResult generateJava() {
new NameExpr(
"using = com.fasterxml.jackson.databind.JsonDeserializer.None.class")));

if (config.isGeneratedAnnotations()) {
clz.addAnnotation(GENERATED_ANNOTATION);
}
if (config.isObjectExtraAnnotations()) {
addExtraAnnotations(clz);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ private static Stream<Arguments> getCRDGenerationInputData() {
return Stream.of(
Arguments.of("testCrontabCrd", "crontab-crd.yml", "CronTab", "CrontabJavaCr", new Config()),
Arguments.of("testCrontabExtraAnnotationsCrd", "crontab-crd.yml", "CronTab", "CrontabJavaExtraAnnotationsCr",
new Config(null, null, null, null, Boolean.TRUE, null)),
new Config(null, null, null, null, Boolean.TRUE, null, true)),
Arguments.of("testKeycloakCrd", "keycloak-crd.yml", "Keycloak", "KeycloakJavaCr", new Config()),
Arguments.of("testJokeCrd", "jokerequests-crd.yml", "JokeRequest", "JokeRequestJavaCr", new Config()),
Arguments.of("testAkkaMicroservicesCrd", "akka-microservices-crd.yml", "AkkaMicroservice", "AkkaMicroserviceJavaCr",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,8 @@ class CompilationTest {

private static TemporaryFolder tmpFolder = TemporaryFolder.builder().build();

CRGeneratorRunner defaultRunner = new CRGeneratorRunner(new Config());
CRGeneratorRunner defaultRunner = new CRGeneratorRunner(
new Config(null, null, null, null, null, Config.CodeStructure.PACKAGE_NESTED, false));

List<JavaFileObject> getSources(File basePath) throws IOException {
List<JavaFileObject> sources = new ArrayList<JavaFileObject>();
Expand Down Expand Up @@ -87,7 +88,7 @@ void testCrontabCRDCompilesWithFlatPackage() throws Exception {
File crd = getCRD("crontab-crd.yml");
File dest = tmpFolder.newFolder("crontab-flat");
CRGeneratorRunner runner = new CRGeneratorRunner(
new Config(null, null, null, null, null, Config.CodeStructure.FLAT));
new Config(null, null, null, null, null, Config.CodeStructure.FLAT, false));

// Act
runner.run(crd, dest);
Expand All @@ -104,7 +105,7 @@ void testCrontabCRDCompilesWithExtraAnnotationsAndUnknownFields() throws Excepti
// Arrange
File crd = getCRD("crontab-crd.yml");
File dest = tmpFolder.newFolder("crontab-extra-annot");
CRGeneratorRunner runner = new CRGeneratorRunner(new Config(null, null, null, true, true, null));
CRGeneratorRunner runner = new CRGeneratorRunner(new Config(null, null, null, true, true, null, false));

// Act
runner.run(crd, dest);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -256,7 +256,7 @@ void testEmptyObject() {
@Test
void testEmptyObjectWithSuffix() {
// Arrange
Config config = new Config(null, null, Config.Suffix.ALWAYS, null, null, null);
Config config = new Config(null, null, Config.Suffix.ALWAYS, null, null, null, true);
JObject obj = new JObject(
"v1alpha1",
"t",
Expand Down Expand Up @@ -368,6 +368,47 @@ void testObjectWithRequiredField() {
assertTrue(clz.get().getFieldByName("o1").get().getAnnotationByName("Required").isPresent());
}

@Test
void testObjectWithAndWithoutGeneratedAnnotation() {
// Arrange
JObject obj1 = new JObject(
"v1alpha1",
"t",
new HashMap<>(),
new ArrayList<>(),
false,
"",
"",
defaultConfig,
null,
Boolean.FALSE,
null);
Config config = new Config(null, null, Config.Suffix.ALWAYS, null, null, null, false);
JObject obj2 = new JObject(
"v1alpha1",
"t",
new HashMap<>(),
new ArrayList<>(),
false,
"",
"",
config,
null,
Boolean.FALSE,
null);

// Act
GeneratorResult res1 = obj1.generateJava();
GeneratorResult res2 = obj2.generateJava();

// Assert
Optional<ClassOrInterfaceDeclaration> clz1 = res1.getTopLevelClasses().get(0).getCompilationUnit().getClassByName("T");
assertTrue(clz1.get().getAnnotationByName(AbstractJSONSchema2Pojo.GENERATED_ANNOTATION.getNameAsString()).isPresent());

Optional<ClassOrInterfaceDeclaration> clz2 = res2.getTopLevelClasses().get(0).getCompilationUnit().getClassByName("T");
assertFalse(clz2.get().getAnnotationByName(AbstractJSONSchema2Pojo.GENERATED_ANNOTATION.getNameAsString()).isPresent());
}

@Test
void testDefaultEnum() {
// Arrange
Expand Down Expand Up @@ -418,7 +459,7 @@ void testNotUppercaseEnum() {
JEnum enu = new JEnum(
"t",
enumValues,
new Config(false, null, null, null, null, null),
new Config(false, null, null, null, null, null, true),
null,
Boolean.FALSE,
null);
Expand Down Expand Up @@ -538,7 +579,7 @@ void testObjectOfObjects() {
@Test
void testObjectOfObjectsWithTopLevelPrefix() {
// Arrange
Config config = new Config(null, Config.Prefix.TOP_LEVEL, null, null, null, null);
Config config = new Config(null, Config.Prefix.TOP_LEVEL, null, null, null, null, true);
Map<String, JSONSchemaProps> props = new HashMap<>();
JSONSchemaProps newObj = new JSONSchemaProps();
newObj.setType("object");
Expand Down Expand Up @@ -568,7 +609,7 @@ void testObjectOfObjectsWithTopLevelPrefix() {
@Test
void testObjectOfObjectsWithAlwaysPrefix() {
// Arrange
Config config = new Config(null, Config.Prefix.ALWAYS, null, null, null, null);
Config config = new Config(null, Config.Prefix.ALWAYS, null, null, null, null, true);
Map<String, JSONSchemaProps> props = new HashMap<>();
JSONSchemaProps newObj = new JSONSchemaProps();
newObj.setType("object");
Expand Down

0 comments on commit ebe482c

Please sign in to comment.