diff --git a/annotations/builder/src/main/java/io/sundr/builder/internal/BuilderContext.java b/annotations/builder/src/main/java/io/sundr/builder/internal/BuilderContext.java index 16ba9f158..a9833a075 100644 --- a/annotations/builder/src/main/java/io/sundr/builder/internal/BuilderContext.java +++ b/annotations/builder/src/main/java/io/sundr/builder/internal/BuilderContext.java @@ -73,11 +73,10 @@ public class BuilderContext { private final TypeDef visitorListenerInterface; private final TypeDef visitorWiretapClass; private final TypeDef delegatingVisitorClass; - private final TypeDef fluentInterface; private final TypeDef builderInterface; private final TypeDef nestedInterface; private final TypeDef editableInterface; - private final TypeDef visitableInterface; + private TypeDef visitableInterface; private final TypeDef visitableBuilderInterface; private final TypeDef visitableMapClass; private final TypeDef inlineableBase; @@ -875,19 +874,6 @@ public BuilderContext(Elements elements, Types types, Boolean generateBuilderPac .accept(new ReplacePackage("io.sundr.builder", builderPackage)) .build(); - fluentInterface = new TypeDefBuilder() - .withNewModifiers().withPublic().endModifiers() - .withKind(Kind.INTERFACE) - .withPackageName("io.sundr.builder") - .withName("Fluent") - .addNewParameter() - .withName("F") - .withBounds( - new ClassRefBuilder().withFullyQualifiedName("io.sundr.builder.Fluent").withArguments(F.toReference()).build()) - .endParameter() - .accept(new ReplacePackage("io.sundr.builder", builderPackage)) - .build(); - nestedInterface = new TypeDefBuilder() .withNewModifiers().withPublic().endModifiers() .withKind(Kind.INTERFACE) @@ -983,6 +969,19 @@ public BuilderContext(Elements elements, Types types, Boolean generateBuilderPac .accept(new ApplyImportsFromResources("io/sundr/builder/VisitableMap.java")) .build(); + // rebuild visitable now that visitableMapClass is available + visitableInterface = new TypeDefBuilder(visitableInterface) + .addNewMethod() + .withDefaultMethod(true) + .withNewModifiers().withPublic().endModifiers() + .withName("getVisitableMap") + .withReturnType(OPTIONAL.toReference(visitableMapClass.toReference())) + .endMethod() + .accept(new ReplacePackage("io.sundr.builder", builderPackage)) + .accept(new ApplyMethodBlockFromResources("Visitable", "io/sundr/builder/Visitable.java", true)) + .accept(new ApplyImportsFromResources("io/sundr/builder/Visitable.java")) + .build(); + baseFluentClass = new TypeDefBuilder() .withNewModifiers().withPublic().endModifiers() .withKind(Kind.CLASS) @@ -990,9 +989,7 @@ public BuilderContext(Elements elements, Types types, Boolean generateBuilderPac .withName("BaseFluent") .addNewParameter() .withName("F") - .withBounds(fluentInterface.toReference(F.toReference())) .endParameter() - .withImplementsList(fluentInterface.toReference(F.toReference()), visitableInterface.toReference(F.toReference())) .addNewProperty() .withNewModifiers().withPublic().withStatic().withFinal().endModifiers() @@ -1077,66 +1074,8 @@ public BuilderContext(Elements elements, Types types, Boolean generateBuilderPac .addNewMethod() .withNewModifiers().withPublic().endModifiers() - .withName("accept") - .withReturnType(F.toReference()) - .addNewArgument() - .withName("visitors") - .withTypeRef(new ClassRefBuilder().withFullyQualifiedName(Visitor.class.getName()).withDimensions(1).build()) - .endArgument() - .withVarArgPreferred(true) - .endMethod() - - .addNewMethod() - .withNewModifiers().withPublic().endModifiers() - .withName("accept") - .withParameters(V) - .withReturnType(F.toReference()) - .addNewArgument() - .withTypeRef(CLASS.toReference(V.toReference())) - .withName("type") - .endArgument() - .addNewArgument() - .withTypeRef(visitorInterface.toReference(V.toReference())) - .withNewModifiers().withFinal().endModifiers() - .withName("visitor") - .endArgument() - .withVarArgPreferred(true) - .endMethod() - - .addNewMethod() - .withNewModifiers().withPublic().endModifiers() - .withName("accept") - .withReturnType(F.toReference()) - .addNewArgument() - .withName("path") - .withTypeRef(Collections.LIST.toReference(Collections.MAP_ENTRY.toReference(STRING_REF, TypeDef.OBJECT_REF))) - .endArgument() - .addNewArgument() - .withTypeRef( - new ClassRefBuilder().withFullyQualifiedName(visitorInterface.getFullyQualifiedName()).withDimensions(1).build()) - .withName("visitors") - .endArgument() - .withVarArgPreferred(true) - .endMethod() - - .addNewMethod() - .withNewModifiers().withPublic().endModifiers() - .withName("accept") - .withReturnType(F.toReference()) - .addNewArgument() - .withName("path") - .withTypeRef(Collections.LIST.toReference(Collections.MAP_ENTRY.toReference(STRING_REF, TypeDef.OBJECT_REF))) - .endArgument() - .addNewArgument() - .withTypeRef(STRING_REF) - .withName("currentKey") - .endArgument() - .addNewArgument() - .withTypeRef( - new ClassRefBuilder().withFullyQualifiedName(visitorInterface.getFullyQualifiedName()).withDimensions(1).build()) - .withName("visitors") - .endArgument() - .withVarArgPreferred(true) + .withName("getVisitableMap") + .withReturnType(OPTIONAL.toReference(visitableMapClass.toReference())) .endMethod() .addNewMethod() @@ -1274,10 +1213,6 @@ public TypeDef getBaseFluentClass() { return baseFluentClass; } - public TypeDef getFluentInterface() { - return fluentInterface; - } - public TypeDef getBuilderInterface() { return builderInterface; } diff --git a/annotations/builder/src/main/java/io/sundr/builder/internal/processor/AbstractBuilderProcessor.java b/annotations/builder/src/main/java/io/sundr/builder/internal/processor/AbstractBuilderProcessor.java index f563cb7c2..1ff2ba00c 100644 --- a/annotations/builder/src/main/java/io/sundr/builder/internal/processor/AbstractBuilderProcessor.java +++ b/annotations/builder/src/main/java/io/sundr/builder/internal/processor/AbstractBuilderProcessor.java @@ -75,7 +75,6 @@ void generateLocalDependenciesIfNeeded() { generate(context.getVisitableBuilderInterface()); generate(context.getVisitableMapClass()); generate(context.getBuilderInterface()); - generate(context.getFluentInterface()); generate(context.getBaseFluentClass()); generate(context.getNestedInterface()); generate(context.getEditableInterface()); diff --git a/core/src/main/java/io/sundr/builder/BaseFluent.java b/core/src/main/java/io/sundr/builder/BaseFluent.java index 7ce36ad66..94d83a2ba 100644 --- a/core/src/main/java/io/sundr/builder/BaseFluent.java +++ b/core/src/main/java/io/sundr/builder/BaseFluent.java @@ -16,18 +16,16 @@ package io.sundr.builder; -import java.util.AbstractMap; import java.util.ArrayList; import java.util.Arrays; -import java.util.Collections; import java.util.LinkedHashSet; import java.util.List; -import java.util.Map.Entry; import java.util.Objects; +import java.util.Optional; import java.util.Set; import java.util.stream.Collectors; -public class BaseFluent> implements Fluent, Visitable { +public class BaseFluent { public final VisitableMap _visitables = new VisitableMap(); @@ -70,75 +68,6 @@ public static Set aggregate(Set... sets) { return new LinkedHashSet(Arrays.stream(sets).filter(Objects::nonNull).collect(Collectors.toSet())); } - @Override - public F accept(Visitor... visitors) { - return accept(Collections.emptyList(), visitors); - } - - @Override - public F accept(Class type, Visitor visitor) { - return accept(Collections.emptyList(), new Visitor() { - @Override - public Class getType() { - return type; - } - - @Override - public void visit(List> path, V element) { - visitor.visit(path, element); - } - - @Override - public void visit(V element) { - visitor.visit(element); - } - }); - } - - @Override - public F accept(List> path, String currentKey, Visitor... visitors) { - List sortedVisitor = new ArrayList<>(); - for (Visitor visitor : visitors) { - visitor = VisitorListener.wrap(visitor); - if (!visitor.canVisit(path, this)) { - continue; - } - sortedVisitor.add(visitor); - } - sortedVisitor.sort((l, r) -> ((Visitor) r).order() - ((Visitor) l).order()); - for (Visitor visitor : sortedVisitor) { - visitor.visit(path, this); - } - - List> copyOfPath = path != null ? new ArrayList(path) : new ArrayList<>(); - copyOfPath.add(new AbstractMap.SimpleEntry<>(currentKey, this)); - - for (Entry entry : _visitables.entrySet()) { - List> newPath = Collections.unmodifiableList(copyOfPath); - - // Copy visitables to avoid ConcurrentModificationException when Visitors add/remove Visitables - for (Visitable visitable : new ArrayList<>((List>) entry.getValue())) { - for (Visitor visitor : visitors) { - if (visitor.getType() != null && visitor.getType().isAssignableFrom(visitable.getClass())) { - visitable.accept(newPath, entry.getKey(), visitor); - } - } - - for (Visitor visitor : visitors) { - if (visitor.getType() == null || !visitor.getType().isAssignableFrom(visitable.getClass())) { - visitable.accept(newPath, entry.getKey(), visitor); - } - } - } - } - return (F) this; - } - - @Override - public F accept(List> path, Visitor... visitors) { - return accept(path, "", visitors); - } - @Override public int hashCode() { final int prime = 31; @@ -157,4 +86,8 @@ public boolean equals(Object obj) { return false; return true; } + + public Optional getVisitableMap() { + return Optional.of(_visitables); + } } diff --git a/core/src/main/java/io/sundr/builder/Fluent.java b/core/src/main/java/io/sundr/builder/Fluent.java deleted file mode 100644 index a1e4ac886..000000000 --- a/core/src/main/java/io/sundr/builder/Fluent.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright 2015 The original authors. - * - * 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 io.sundr.builder; - -/** - * The base interface for Fluent interfaces. - * Implementers of this interface are usually classes that need to provide chained method calls (e.g. Builders). - * - * @param The type that is expected to be returned by the Fluent methods. - */ -public interface Fluent> { - -} diff --git a/core/src/main/java/io/sundr/builder/Visitable.java b/core/src/main/java/io/sundr/builder/Visitable.java index 7b68c6979..e624b2e6b 100644 --- a/core/src/main/java/io/sundr/builder/Visitable.java +++ b/core/src/main/java/io/sundr/builder/Visitable.java @@ -17,19 +17,31 @@ package io.sundr.builder; +import java.util.AbstractMap; +import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Map.Entry; +import java.util.Optional; public interface Visitable { + default T accept(Visitor... visitors) { + return accept(Collections.emptyList(), visitors); + } + default T accept(Class type, Visitor visitor) { - return accept(new Visitor() { + return accept(Collections.emptyList(), new Visitor() { @Override public Class getType() { return type; } + @Override + public void visit(List> path, V element) { + visitor.visit(path, element); + } + @Override public void visit(V element) { visitor.visit(element); @@ -37,29 +49,56 @@ public void visit(V element) { }); } - default T accept(Visitor... visitors) { - for (Visitor visitor : visitors) { - if (visitor.canVisit(Collections.emptyList(), this)) { - visitor.visit(this); - } - } - return getTarget(this); + default T accept(List> path, Visitor... visitors) { + return accept(path, "", visitors); } - default T accept(List> path, String currentKey, Visitor... visitors) { + default T accept(List> path, String currentKey, Visitor... visitors) { + List sortedVisitor = new ArrayList<>(); for (Visitor visitor : visitors) { - if (visitor.canVisit(path, this)) { - visitor.visit(path, this); + visitor = VisitorListener.wrap(visitor); + if (!visitor.canVisit(path, this)) { + continue; } + sortedVisitor.add(visitor); + } + sortedVisitor.sort((l, r) -> ((Visitor) r).order() - ((Visitor) l).order()); + for (Visitor visitor : sortedVisitor) { + visitor.visit(path, this); } - return getTarget(this); - } - default T accept(List> path, Visitor... visitors) { - return accept(path, "", visitors); + List> copyOfPath = path != null ? new ArrayList(path) : new ArrayList<>(); + copyOfPath.add(new AbstractMap.SimpleEntry<>(currentKey, this)); + + getVisitableMap().ifPresent(vm -> { + for (Entry entry : vm.entrySet()) { + List> newPath = Collections.unmodifiableList(copyOfPath); + + // Copy visitables to avoid ConcurrentModificationException when Visitors add/remove Visitables + for (Visitable visitable : new ArrayList<>((List>) entry.getValue())) { + for (Visitor visitor : visitors) { + if (visitor.getType() != null && visitor.getType().isAssignableFrom(visitable.getClass())) { + visitable.accept(newPath, entry.getKey(), visitor); + } + } + + for (Visitor visitor : visitors) { + if (visitor.getType() == null || !visitor.getType().isAssignableFrom(visitable.getClass())) { + visitable.accept(newPath, entry.getKey(), visitor); + } + } + } + } + }); + + return (T) this; } default T getTarget(Visitable visitable) { return (T) visitable; } + + default Optional getVisitableMap() { + return Optional.empty(); + } } diff --git a/model/utils/src/main/java/io/sundr/model/visitors/ReplacePackage.java b/model/utils/src/main/java/io/sundr/model/visitors/ReplacePackage.java index dd41e8c0f..688f5504b 100644 --- a/model/utils/src/main/java/io/sundr/model/visitors/ReplacePackage.java +++ b/model/utils/src/main/java/io/sundr/model/visitors/ReplacePackage.java @@ -17,6 +17,7 @@ package io.sundr.model.visitors; import java.util.ArrayList; +import java.util.Collection; import java.util.LinkedHashSet; import java.util.List; import java.util.Set; @@ -49,6 +50,7 @@ public void visit(ClassRefFluent ref) { }; } + @Override public void visit(Builder builder) { if (builder instanceof TypeDefBuilder) { visitTypeDefBuilder((TypeDefBuilder) builder); @@ -97,7 +99,7 @@ private void visitTypeDefBuilder(TypeDefBuilder builder) { if (builder.getAttributes().containsKey(TypeDef.ALSO_IMPORT)) { Set updatedImports = new LinkedHashSet(); - for (ClassRef classRef : (Set) builder.getAttributes().get(TypeDef.ALSO_IMPORT)) { + for (ClassRef classRef : (Collection) builder.getAttributes().get(TypeDef.ALSO_IMPORT)) { if (target.equals(classRef.getPackageName())) { updatedImports.add(new ClassRefBuilder(classRef).accept(this).build()); } else {