Skip to content

Commit

Permalink
adding back dependent class names
Browse files Browse the repository at this point in the history
  • Loading branch information
shawkins committed Apr 30, 2024
1 parent 006f6a7 commit 6c2ce80
Show file tree
Hide file tree
Showing 7 changed files with 74 additions and 37 deletions.
Expand Up @@ -22,6 +22,8 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import java.util.stream.Stream;

Expand Down Expand Up @@ -68,6 +70,6 @@ protected void handlePrinterColumns(AbstractJsonSchema<?, ?> resolver, PrinterCo
});
}

public abstract Stream<HasMetadata> finish();
public abstract Stream<Map.Entry<? extends HasMetadata, Set<String>>> finish();

}
Expand Up @@ -21,7 +21,6 @@
import com.fasterxml.jackson.databind.BeanDescription;
import com.fasterxml.jackson.databind.BeanProperty;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.introspect.AnnotatedMethod;
import com.fasterxml.jackson.databind.node.JsonNodeFactory;
Expand Down Expand Up @@ -92,6 +91,7 @@ public abstract class AbstractJsonSchema<T extends KubernetesJSONSchemaProps, V

private ResolvingContext resolvingContext;
private T root;
private Set<String> dependentClasses = new HashSet<>();

public static class AnnotationMetadata {
public final Annotation annotation;
Expand All @@ -118,6 +118,10 @@ public T getSchema() {
return root;
}

public Set<String> getDependentClasses() {
return dependentClasses;
}

public Optional<String> getSinglePath(Class<? extends Annotation> clazz) {
return ofNullable(pathMetadata.get(clazz)).flatMap(m -> m.keySet().stream().findFirst());
}
Expand All @@ -136,7 +140,7 @@ public Map<String, AnnotationMetadata> getAllPaths(Class<PrinterColumn> clazz) {
*/
private T resolveRoot(Class<?> definition) {
InternalSchemaSwaps schemaSwaps = new InternalSchemaSwaps();
JsonSchema schema = toJsonSchema(definition);
JsonSchema schema = resolvingContext.toJsonSchema(definition);
if (schema instanceof GeneratorObjectSchema) {
return resolveObject(new LinkedHashMap<>(), schemaSwaps, schema, "kind", "apiVersion", "metadata");
}
Expand Down Expand Up @@ -285,8 +289,11 @@ private T resolveObject(LinkedHashMap<String, String> visited, InternalSchemaSwa
preserveUnknownFields = bd.findAnyGetter() != null || bd.findAnySetterAccessor() != null;
}

consumeRepeatingAnnotation(gos.javaType.getRawClass(), SchemaSwap.class, ss -> {
swaps.registerSwap(gos.javaType.getRawClass(),
Class<?> rawClass = gos.javaType.getRawClass();
collectDependentClasses(rawClass);

consumeRepeatingAnnotation(rawClass, SchemaSwap.class, ss -> {
swaps.registerSwap(rawClass,
ss.originalType(),
ss.fieldName(),
ss.targetType(), ss.depth());
Expand All @@ -300,7 +307,7 @@ private T resolveObject(LinkedHashMap<String, String> visited, InternalSchemaSwa
continue;
}
schemaSwaps = schemaSwaps.branchDepths();
SwapResult swapResult = schemaSwaps.lookupAndMark(gos.javaType.getRawClass(), name);
SwapResult swapResult = schemaSwaps.lookupAndMark(rawClass, name);
LinkedHashMap<String, String> savedVisited = visited;
if (swapResult.onGoing) {
visited = new LinkedHashMap<>();
Expand Down Expand Up @@ -331,7 +338,7 @@ private T resolveObject(LinkedHashMap<String, String> visited, InternalSchemaSwa
// fully omit - this is a little inconsistent with the NullSchema handling
continue;
}
propertySchema = toJsonSchema(propertyMetadata.schemaFrom);
propertySchema = resolvingContext.toJsonSchema(propertyMetadata.schemaFrom);
type = resolvingContext.objectMapper.getSerializationConfig().constructType(propertyMetadata.schemaFrom);
}

Expand Down Expand Up @@ -359,12 +366,20 @@ private T resolveObject(LinkedHashMap<String, String> visited, InternalSchemaSwa
objectSchema.setXKubernetesPreserveUnknownFields(true);
}
List<V> validationRules = new ArrayList<>();
consumeRepeatingAnnotation(gos.javaType.getRawClass(), ValidationRule.class,
consumeRepeatingAnnotation(rawClass, ValidationRule.class,
v -> validationRules.add(from(v)));
addToValidationRules(objectSchema, validationRules);
return objectSchema;
}

private void collectDependentClasses(Class<?> rawClass) {
Stream.of(rawClass.getInterfaces()).map(Class::getName).forEach(dependentClasses::add);
while (rawClass != null) {
dependentClasses.add(rawClass.getName());
rawClass = rawClass.getSuperclass();
}
}

static String toFQN(LinkedHashMap<String, String> visited, String name) {
if (visited.isEmpty()) {
return "." + name;
Expand Down Expand Up @@ -494,14 +509,6 @@ private static String mapNotEmpty(String s) {
return Utils.isNullOrEmpty(s) ? null : s;
}

private JsonSchema toJsonSchema(Class<?> clazz) {
try {
return resolvingContext.generator.generateSchema(clazz);
} catch (JsonMappingException e) {
throw new RuntimeException(e);
}
}

protected abstract V newKubernetesValidationRule();

/**
Expand Down
Expand Up @@ -19,6 +19,7 @@
import java.net.URI;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

public class CRDGenerationInfo {

Expand All @@ -33,9 +34,9 @@ public Map<String, Map<String, CRDInfo>> getCRDDetailsPerNameAndVersion() {
return crdNameToVersionToCRDInfoMap;
}

void add(String crdName, String version, URI fileURI) {
void add(String crdName, String version, URI fileURI, Set<String> dependentClassNames) {
crdNameToVersionToCRDInfoMap.computeIfAbsent(crdName, k -> new HashMap<>())
.put(version, new CRDInfo(crdName, version, new File(fileURI).getAbsolutePath()));
.put(version, new CRDInfo(crdName, version, new File(fileURI).getAbsolutePath(), dependentClassNames));
}

public int numberOfGeneratedCRDs() {
Expand Down
Expand Up @@ -28,6 +28,7 @@
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.net.URI;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
Expand Down Expand Up @@ -173,29 +174,28 @@ public CRDGenerationInfo detailedGenerate() {
handlers.values().stream().map(h -> ForkJoinPool.commonPool().submit(() -> h.handle(info, context.forkContext())))
.collect(Collectors.toList()).stream().forEach(ForkJoinTask::join);
} else {
handlers.values().stream().forEach(h -> h.handle(info, context));
handlers.values().stream().forEach(h -> h.handle(info, context.forkContext()));
}
}
}

final CRDGenerationInfo crdGenerationInfo = new CRDGenerationInfo();
handlers.values().stream().flatMap(AbstractCustomResourceHandler::finish).forEach(crd -> emitCrd(crd, crdGenerationInfo));
handlers.values().stream().flatMap(AbstractCustomResourceHandler::finish)
.forEach(crd -> emitCrd(crd.getKey(), crd.getValue(), crdGenerationInfo));
return crdGenerationInfo;
}

public void emitCrd(HasMetadata crd, CRDGenerationInfo crdGenerationInfo) {
public void emitCrd(HasMetadata crd, Set<String> dependentClassNames, CRDGenerationInfo crdGenerationInfo) {
final String version = ApiVersionUtil.trimVersion(crd.getApiVersion());
final String crdName = crd.getMetadata().getName();
try {
final String outputName = getOutputName(crdName, version);
try (final OutputStream outputStream = output.outputFor(outputName)) {
outputStream.write(
"# Generated by Fabric8 CRDGenerator, manual edits might get overwritten!\n"
.getBytes());
try (final OutputStreamWriter writer = new OutputStreamWriter(output.outputFor(outputName), StandardCharsets.UTF_8)) {
writer.write("# Generated by Fabric8 CRDGenerator, manual edits might get overwritten!\n");
String yaml = kubernetesSerialization.asYaml(crd);
outputStream.write(yaml.getBytes(StandardCharsets.UTF_8));
writer.write(yaml);
final URI fileURI = output.crdURI(outputName);
crdGenerationInfo.add(crdName, version, fileURI);
crdGenerationInfo.add(crdName, version, fileURI, dependentClassNames);
}
} catch (IOException e) {
throw new RuntimeException(e);
Expand Down
Expand Up @@ -15,15 +15,19 @@
*/
package io.fabric8.crdv2.generator;

import java.util.Set;

public class CRDInfo {
private final String crdName;
private final String crdSpecVersion;
private final String filePath;
private final Set<String> dependentClassNames;

public CRDInfo(String crdName, String crdSpecVersion, String filePath) {
public CRDInfo(String crdName, String crdSpecVersion, String filePath, Set<String> dependentClassNames) {
this.crdName = crdName;
this.crdSpecVersion = crdSpecVersion;
this.filePath = filePath;
this.dependentClassNames = dependentClassNames;
}

public String getCrdName() {
Expand All @@ -38,4 +42,8 @@ public String getFilePath() {
return filePath;
}

public Set<String> getDependentClassNames() {
return dependentClassNames;
}

}
Expand Up @@ -18,6 +18,7 @@

import com.fasterxml.jackson.databind.BeanProperty;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.jsonFormatVisitors.JsonObjectFormatVisitor;
Expand Down Expand Up @@ -143,4 +144,12 @@ public SchemaFactoryWrapper getWrapper(SerializerProvider provider, VisitorConte
});
}

JsonSchema toJsonSchema(Class<?> clazz) {
try {
return generator.generateSchema(clazz);
} catch (JsonMappingException e) {
throw new RuntimeException(e);
}
}

}
Expand Up @@ -31,16 +31,20 @@
import io.fabric8.kubernetes.model.annotation.SpecReplicas;
import io.fabric8.kubernetes.model.annotation.StatusReplicas;

import java.util.AbstractMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Optional;
import java.util.Queue;
import java.util.Set;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class CustomResourceHandler extends AbstractCustomResourceHandler {

private Queue<CustomResourceDefinition> crds = new ConcurrentLinkedQueue<>();
private Queue<Map.Entry<CustomResourceDefinition, Set<String>>> crds = new ConcurrentLinkedQueue<>();

public static final String VERSION = "v1";

Expand Down Expand Up @@ -111,24 +115,28 @@ public void addPrinterColumn(String path, String column, String format, int prio
.endSpec()
.build();

crds.add(crd);
crds.add(new AbstractMap.SimpleEntry<>(crd, resolver.getDependentClasses()));
}

@Override
public Stream<HasMetadata> finish() {
return crds.stream().collect(Collectors.groupingBy(crd -> crd.getMetadata().getName())).values().stream()
public Stream<Entry<? extends HasMetadata, Set<String>>> finish() {
return crds.stream().collect(Collectors.groupingBy(crd -> crd.getKey().getMetadata().getName())).values().stream()
.map(this::combine);
}

private CustomResourceDefinition combine(List<CustomResourceDefinition> definitions) {
CustomResourceDefinition primary = definitions.get(0);
private Map.Entry<CustomResourceDefinition, Set<String>> combine(
List<Map.Entry<CustomResourceDefinition, Set<String>>> definitions) {
Map.Entry<CustomResourceDefinition, Set<String>> primary = definitions.get(0);
if (definitions.size() == 1) {
return primary;
}

List<CustomResourceDefinitionVersion> versions = definitions.stream().flatMap(crd -> crd.getSpec().getVersions().stream())
List<CustomResourceDefinitionVersion> versions = definitions.stream()
.flatMap(crd -> crd.getKey().getSpec().getVersions().stream())
.collect(Collectors.toList());

Set<String> allDependentClasses = definitions.stream().flatMap(crd -> crd.getValue().stream()).collect(Collectors.toSet());

List<String> storageVersions = versions.stream()
.filter(v -> Optional.ofNullable(v.getStorage()).orElse(true))
.map(CustomResourceDefinitionVersion::getName)
Expand All @@ -137,13 +145,15 @@ private CustomResourceDefinition combine(List<CustomResourceDefinition> definiti
if (storageVersions.size() > 1) {
throw new IllegalStateException(String.format(
"'%s' custom resource has versions %s marked as storage. Only one version can be marked as storage per custom resource.",
primary.getMetadata().getName(), storageVersions));
primary.getKey().getMetadata().getName(), storageVersions));
}

versions = KubernetesVersionPriority.sortByPriority(versions, CustomResourceDefinitionVersion::getName);

//TODO: we could double check that the top-level metadata is consistent across all versions
return new CustomResourceDefinitionBuilder(primary).editSpec().withVersions(versions).endSpec().build();
return new AbstractMap.SimpleEntry<>(
new CustomResourceDefinitionBuilder(primary.getKey()).editSpec().withVersions(versions).endSpec().build(),
allDependentClasses);
}

}

0 comments on commit 6c2ce80

Please sign in to comment.