From 8797c7830f4fbe9b4154298e5af390d35f8f3481 Mon Sep 17 00:00:00 2001 From: Bence Gelei Date: Mon, 13 Jan 2025 11:21:45 +0100 Subject: [PATCH 1/6] JNG-6082 Initial feature commit [ci skip] From 8a221ade8b07b3769c68b036b757ad6737b8cd0c Mon Sep 17 00:00:00 2001 From: Bence Gelei Date: Mon, 13 Jan 2025 11:52:34 +0100 Subject: [PATCH 2/6] payload traverser added --- pom.xml | 6 + .../judo/dao/api/PayloadTraverser.java | 258 ++++++++++++++++++ 2 files changed, 264 insertions(+) create mode 100644 src/main/java/hu/blackbelt/judo/dao/api/PayloadTraverser.java diff --git a/pom.xml b/pom.xml index c9e4d82..a125f05 100644 --- a/pom.xml +++ b/pom.xml @@ -114,6 +114,12 @@ 2.12.0 provided + + org.eclipse.emf + org.eclipse.emf.common + 2.12.0 + provided + com.fasterxml.jackson.datatype diff --git a/src/main/java/hu/blackbelt/judo/dao/api/PayloadTraverser.java b/src/main/java/hu/blackbelt/judo/dao/api/PayloadTraverser.java new file mode 100644 index 0000000..7748b6e --- /dev/null +++ b/src/main/java/hu/blackbelt/judo/dao/api/PayloadTraverser.java @@ -0,0 +1,258 @@ +package hu.blackbelt.judo.dao.api; + +/*- + * #%L + * JUDO Runtime Core :: Parent + * %% + * Copyright (C) 2018 - 2022 BlackBelt Technology + * %% + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the Eclipse + * Public License, v. 2.0 are satisfied: GNU General Public License, version 2 + * with the GNU Classpath Exception which is + * available at https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + * #L% + */ + +import java.util.Collection; +import java.util.Collections; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.function.BiConsumer; +import java.util.function.Function; +import java.util.function.Predicate; +import java.util.stream.Collector; +import java.util.stream.Collectors; + +import com.google.common.collect.ImmutableList; +import lombok.NonNull; +import org.eclipse.emf.ecore.EClass; +import org.eclipse.emf.ecore.EReference; +import org.eclipse.emf.ecore.EStructuralFeature; +import org.eclipse.emf.ecore.ETypedElement; + +public class PayloadTraverser { + + @NonNull + private BiConsumer processor; + + @NonNull + private Predicate predicate; + + private static final Predicate IS_COLLECTION = ETypedElement::isMany; + + PayloadTraverser(@NonNull BiConsumer processor, @NonNull Predicate predicate) { + this.processor = processor; + this.predicate = predicate; + } + + public static PayloadTraverserBuilder builder() { + return new PayloadTraverserBuilder(); + } + + public Payload traverse(final Payload payload, final EClass transferObjectType) { + return traverse(payload, PayloadTraverserContext + .builder() + .type(transferObjectType) + .path(Collections.emptyList()) + .build()); + } + + private Payload traverse(final Payload payload, final PayloadTraverserContext ctx) { + if (payload == null) { + return null; + } + + processor.accept(payload, ctx); + + ctx.getType().getEAllReferences().stream() + .filter(predicate) + .filter(r -> payload.containsKey(r.getName()) && payload.get(r.getName()) != null) + .collect(toReferencePayloadMapOfPayloadCollection(payload)) + .forEach((key, value) -> { + int idx = 0; + for (Iterator it = value.iterator(); it.hasNext(); idx++) { + final Payload p = it.next(); + traverse(p, PayloadTraverserContext.builder() + .type(key.getEReferenceType()) + .path(ImmutableList.builder() + .addAll(ctx.getPath()) + .add(PathEntry.builder() + .reference(key) + .index(idx) + .build()) + .build()) + .build()); + } + }); + + return payload; + } + + private static Collector>> toReferencePayloadMapOfPayloadCollection(Payload payload) { + return Collectors.toMap(Function.identity(), (r) -> { + if (IS_COLLECTION.test(r)) { + return payload.getAsCollectionPayload(r.getName()); + } else { + return ImmutableList.of(payload.getAsPayload(r.getName())); + } + }); + } + + public @NonNull BiConsumer getProcessor() { + return this.processor; + } + + public @NonNull Predicate getPredicate() { + return this.predicate; + } + + public static class PayloadTraverserContext { + + @NonNull + private EClass type; + + @NonNull + private List path; + + PayloadTraverserContext(@NonNull EClass type, @NonNull List path) { + this.type = type; + this.path = path; + } + + public static PayloadTraverserContextBuilder builder() { + return new PayloadTraverserContextBuilder(); + } + + public String getPathAsString() { + return path.stream().map(e -> e.getReference().getName() + (e.getReference().isMany() ? "[" + e.getIndex() + "]" : "")).collect(Collectors.joining(".")); + } + + public @NonNull EClass getType() { + return this.type; + } + + public @NonNull List getPath() { + return this.path; + } + + public static class PayloadTraverserContextBuilder { + + private @NonNull EClass type; + private @NonNull List path; + + PayloadTraverserContextBuilder() { + } + + public PayloadTraverserContextBuilder type(@NonNull EClass type) { + this.type = type; + return this; + } + + public PayloadTraverserContextBuilder path(@NonNull List path) { + this.path = path; + return this; + } + + public PayloadTraverserContext build() { + return new PayloadTraverserContext(this.type, this.path); + } + + public String toString() { + return "PayloadTraverser.PayloadTraverserContext.PayloadTraverserContextBuilder(type=" + this.type + ", path=" + this.path + ")"; + } + + } + + } + + public static class PathEntry { + + @NonNull + private final EReference reference; + + private final Integer index; + + PathEntry(@NonNull EReference reference, Integer index) { + this.reference = reference; + this.index = index; + } + + public static PathEntryBuilder builder() { + return new PathEntryBuilder(); + } + + public @NonNull EReference getReference() { + return this.reference; + } + + public Integer getIndex() { + return this.index; + } + + public static class PathEntryBuilder { + + private @NonNull EReference reference; + private Integer index; + + PathEntryBuilder() { + } + + public PathEntryBuilder reference(@NonNull EReference reference) { + this.reference = reference; + return this; + } + + public PathEntryBuilder index(Integer index) { + this.index = index; + return this; + } + + public PathEntry build() { + return new PathEntry(this.reference, this.index); + } + + public String toString() { + return "PayloadTraverser.PathEntry.PathEntryBuilder(reference=" + this.reference + ", index=" + this.index + ")"; + } + + } + + } + + public static class PayloadTraverserBuilder { + + private @NonNull BiConsumer processor; + private @NonNull Predicate predicate; + + PayloadTraverserBuilder() { + } + + public PayloadTraverserBuilder processor(@NonNull BiConsumer processor) { + this.processor = processor; + return this; + } + + public PayloadTraverserBuilder predicate(@NonNull Predicate predicate) { + this.predicate = predicate; + return this; + } + + public PayloadTraverser build() { + return new PayloadTraverser(this.processor, this.predicate); + } + + public String toString() { + return "PayloadTraverser.PayloadTraverserBuilder(processor=" + this.processor + ", predicate=" + this.predicate + ")"; + } + + } + +} From 6b4e7526ff462678a80f77acdb7ef9c634b38105 Mon Sep 17 00:00:00 2001 From: Bence Gelei Date: Wed, 15 Jan 2025 17:28:56 +0100 Subject: [PATCH 3/6] default populator added --- .../java/hu/blackbelt/judo/dao/api/DAO.java | 10 + .../judo/dao/api/PayloadTraverser.java | 258 ------------------ 2 files changed, 10 insertions(+), 258 deletions(-) delete mode 100644 src/main/java/hu/blackbelt/judo/dao/api/PayloadTraverser.java diff --git a/src/main/java/hu/blackbelt/judo/dao/api/DAO.java b/src/main/java/hu/blackbelt/judo/dao/api/DAO.java index db55e24..dda3d2f 100644 --- a/src/main/java/hu/blackbelt/judo/dao/api/DAO.java +++ b/src/main/java/hu/blackbelt/judo/dao/api/DAO.java @@ -65,6 +65,16 @@ public interface DAO { */ Payload getDefaultsOf(EClass clazz); + /** + *

Populate the default values in the given payload based on the specified transfer object type.

+ *

The payload is also populated by traversing through its relations.

+ * + * @param clazz transfer object type + * @param payload payload + * @return copy of given payload with populated default values + */ + Payload populateDefaultsOf(EClass clazz, Payload payload); + /** * Get range of a given transfer object relation. * diff --git a/src/main/java/hu/blackbelt/judo/dao/api/PayloadTraverser.java b/src/main/java/hu/blackbelt/judo/dao/api/PayloadTraverser.java deleted file mode 100644 index 7748b6e..0000000 --- a/src/main/java/hu/blackbelt/judo/dao/api/PayloadTraverser.java +++ /dev/null @@ -1,258 +0,0 @@ -package hu.blackbelt.judo.dao.api; - -/*- - * #%L - * JUDO Runtime Core :: Parent - * %% - * Copyright (C) 2018 - 2022 BlackBelt Technology - * %% - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0. - * - * This Source Code may also be made available under the following Secondary - * Licenses when the conditions for such availability set forth in the Eclipse - * Public License, v. 2.0 are satisfied: GNU General Public License, version 2 - * with the GNU Classpath Exception which is - * available at https://www.gnu.org/software/classpath/license.html. - * - * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 - * #L% - */ - -import java.util.Collection; -import java.util.Collections; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.function.BiConsumer; -import java.util.function.Function; -import java.util.function.Predicate; -import java.util.stream.Collector; -import java.util.stream.Collectors; - -import com.google.common.collect.ImmutableList; -import lombok.NonNull; -import org.eclipse.emf.ecore.EClass; -import org.eclipse.emf.ecore.EReference; -import org.eclipse.emf.ecore.EStructuralFeature; -import org.eclipse.emf.ecore.ETypedElement; - -public class PayloadTraverser { - - @NonNull - private BiConsumer processor; - - @NonNull - private Predicate predicate; - - private static final Predicate IS_COLLECTION = ETypedElement::isMany; - - PayloadTraverser(@NonNull BiConsumer processor, @NonNull Predicate predicate) { - this.processor = processor; - this.predicate = predicate; - } - - public static PayloadTraverserBuilder builder() { - return new PayloadTraverserBuilder(); - } - - public Payload traverse(final Payload payload, final EClass transferObjectType) { - return traverse(payload, PayloadTraverserContext - .builder() - .type(transferObjectType) - .path(Collections.emptyList()) - .build()); - } - - private Payload traverse(final Payload payload, final PayloadTraverserContext ctx) { - if (payload == null) { - return null; - } - - processor.accept(payload, ctx); - - ctx.getType().getEAllReferences().stream() - .filter(predicate) - .filter(r -> payload.containsKey(r.getName()) && payload.get(r.getName()) != null) - .collect(toReferencePayloadMapOfPayloadCollection(payload)) - .forEach((key, value) -> { - int idx = 0; - for (Iterator it = value.iterator(); it.hasNext(); idx++) { - final Payload p = it.next(); - traverse(p, PayloadTraverserContext.builder() - .type(key.getEReferenceType()) - .path(ImmutableList.builder() - .addAll(ctx.getPath()) - .add(PathEntry.builder() - .reference(key) - .index(idx) - .build()) - .build()) - .build()); - } - }); - - return payload; - } - - private static Collector>> toReferencePayloadMapOfPayloadCollection(Payload payload) { - return Collectors.toMap(Function.identity(), (r) -> { - if (IS_COLLECTION.test(r)) { - return payload.getAsCollectionPayload(r.getName()); - } else { - return ImmutableList.of(payload.getAsPayload(r.getName())); - } - }); - } - - public @NonNull BiConsumer getProcessor() { - return this.processor; - } - - public @NonNull Predicate getPredicate() { - return this.predicate; - } - - public static class PayloadTraverserContext { - - @NonNull - private EClass type; - - @NonNull - private List path; - - PayloadTraverserContext(@NonNull EClass type, @NonNull List path) { - this.type = type; - this.path = path; - } - - public static PayloadTraverserContextBuilder builder() { - return new PayloadTraverserContextBuilder(); - } - - public String getPathAsString() { - return path.stream().map(e -> e.getReference().getName() + (e.getReference().isMany() ? "[" + e.getIndex() + "]" : "")).collect(Collectors.joining(".")); - } - - public @NonNull EClass getType() { - return this.type; - } - - public @NonNull List getPath() { - return this.path; - } - - public static class PayloadTraverserContextBuilder { - - private @NonNull EClass type; - private @NonNull List path; - - PayloadTraverserContextBuilder() { - } - - public PayloadTraverserContextBuilder type(@NonNull EClass type) { - this.type = type; - return this; - } - - public PayloadTraverserContextBuilder path(@NonNull List path) { - this.path = path; - return this; - } - - public PayloadTraverserContext build() { - return new PayloadTraverserContext(this.type, this.path); - } - - public String toString() { - return "PayloadTraverser.PayloadTraverserContext.PayloadTraverserContextBuilder(type=" + this.type + ", path=" + this.path + ")"; - } - - } - - } - - public static class PathEntry { - - @NonNull - private final EReference reference; - - private final Integer index; - - PathEntry(@NonNull EReference reference, Integer index) { - this.reference = reference; - this.index = index; - } - - public static PathEntryBuilder builder() { - return new PathEntryBuilder(); - } - - public @NonNull EReference getReference() { - return this.reference; - } - - public Integer getIndex() { - return this.index; - } - - public static class PathEntryBuilder { - - private @NonNull EReference reference; - private Integer index; - - PathEntryBuilder() { - } - - public PathEntryBuilder reference(@NonNull EReference reference) { - this.reference = reference; - return this; - } - - public PathEntryBuilder index(Integer index) { - this.index = index; - return this; - } - - public PathEntry build() { - return new PathEntry(this.reference, this.index); - } - - public String toString() { - return "PayloadTraverser.PathEntry.PathEntryBuilder(reference=" + this.reference + ", index=" + this.index + ")"; - } - - } - - } - - public static class PayloadTraverserBuilder { - - private @NonNull BiConsumer processor; - private @NonNull Predicate predicate; - - PayloadTraverserBuilder() { - } - - public PayloadTraverserBuilder processor(@NonNull BiConsumer processor) { - this.processor = processor; - return this; - } - - public PayloadTraverserBuilder predicate(@NonNull Predicate predicate) { - this.predicate = predicate; - return this; - } - - public PayloadTraverser build() { - return new PayloadTraverser(this.processor, this.predicate); - } - - public String toString() { - return "PayloadTraverser.PayloadTraverserBuilder(processor=" + this.processor + ", predicate=" + this.predicate + ")"; - } - - } - -} From 39089cad7222345c4a42487caaef46794b1d72fb Mon Sep 17 00:00:00 2001 From: Bence Gelei Date: Wed, 15 Jan 2025 19:09:37 +0100 Subject: [PATCH 4/6] rename --- src/main/java/hu/blackbelt/judo/dao/api/DAO.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/java/hu/blackbelt/judo/dao/api/DAO.java b/src/main/java/hu/blackbelt/judo/dao/api/DAO.java index dda3d2f..8b966d1 100644 --- a/src/main/java/hu/blackbelt/judo/dao/api/DAO.java +++ b/src/main/java/hu/blackbelt/judo/dao/api/DAO.java @@ -66,14 +66,14 @@ public interface DAO { Payload getDefaultsOf(EClass clazz); /** - *

Populate the default values in the given payload based on the specified transfer object type.

- *

The payload is also populated by traversing through its relations.

+ *

Apply the default values in the given payload based on the specified transfer object type.

+ *

The default values are also applied by traversing through its relations.

* * @param clazz transfer object type * @param payload payload - * @return copy of given payload with populated default values + * @return copy of given payload with Applied default values */ - Payload populateDefaultsOf(EClass clazz, Payload payload); + Payload applyDefaultsOf(EClass clazz, Payload payload); /** * Get range of a given transfer object relation. From 691e7ac11427a5a49a0f91472631333cca04dda0 Mon Sep 17 00:00:00 2001 From: Bence Gelei Date: Thu, 16 Jan 2025 15:08:44 +0100 Subject: [PATCH 5/6] apply instead of copy --- src/main/java/hu/blackbelt/judo/dao/api/DAO.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main/java/hu/blackbelt/judo/dao/api/DAO.java b/src/main/java/hu/blackbelt/judo/dao/api/DAO.java index 8b966d1..38a4bf7 100644 --- a/src/main/java/hu/blackbelt/judo/dao/api/DAO.java +++ b/src/main/java/hu/blackbelt/judo/dao/api/DAO.java @@ -68,12 +68,13 @@ public interface DAO { /** *

Apply the default values in the given payload based on the specified transfer object type.

*

The default values are also applied by traversing through its relations.

+ *

NOTE: additional fields with default values on entity type that are not targeted by a mapping from given transfer object (clazz) mapping, + * will not be applied

* * @param clazz transfer object type * @param payload payload - * @return copy of given payload with Applied default values */ - Payload applyDefaultsOf(EClass clazz, Payload payload); + void applyDefaultsOf(EClass clazz, Payload payload); /** * Get range of a given transfer object relation. From 46563767464b11fe815f801fa87eca5da1759a5d Mon Sep 17 00:00:00 2001 From: Bence Gelei Date: Sun, 19 Jan 2025 19:54:06 +0100 Subject: [PATCH 6/6] restore pom.xml change --- pom.xml | 6 ------ 1 file changed, 6 deletions(-) diff --git a/pom.xml b/pom.xml index a125f05..c9e4d82 100644 --- a/pom.xml +++ b/pom.xml @@ -114,12 +114,6 @@ 2.12.0 provided
- - org.eclipse.emf - org.eclipse.emf.common - 2.12.0 - provided - com.fasterxml.jackson.datatype