From af1e40c1d649d8608e7dbc3a0abfad5627ec74cd Mon Sep 17 00:00:00 2001 From: Michael Simons Date: Tue, 2 Apr 2024 14:30:38 +0200 Subject: [PATCH] fix: Look for static labels to contain a label, not vice versa. (#2887) Fixes #2886. --- .../mapping/DefaultNeo4jPersistentEntity.java | 7 +++ .../core/mapping/NodeDescriptionStore.java | 8 +-- .../neo4j/integration/issues/IssuesIT.java | 30 +++++++++++ .../integration/issues/gh2886/Apple.java | 25 +++++++++ .../integration/issues/gh2886/Fruit.java | 51 +++++++++++++++++++ .../issues/gh2886/FruitRepository.java | 31 +++++++++++ .../issues/gh2886/MagicalFruit.java | 45 ++++++++++++++++ .../integration/issues/gh2886/Orange.java | 25 +++++++++ 8 files changed, 218 insertions(+), 4 deletions(-) create mode 100644 src/test/java/org/springframework/data/neo4j/integration/issues/gh2886/Apple.java create mode 100644 src/test/java/org/springframework/data/neo4j/integration/issues/gh2886/Fruit.java create mode 100644 src/test/java/org/springframework/data/neo4j/integration/issues/gh2886/FruitRepository.java create mode 100644 src/test/java/org/springframework/data/neo4j/integration/issues/gh2886/MagicalFruit.java create mode 100644 src/test/java/org/springframework/data/neo4j/integration/issues/gh2886/Orange.java diff --git a/src/main/java/org/springframework/data/neo4j/core/mapping/DefaultNeo4jPersistentEntity.java b/src/main/java/org/springframework/data/neo4j/core/mapping/DefaultNeo4jPersistentEntity.java index 5e8f0e4eb..9b75fcb8f 100644 --- a/src/main/java/org/springframework/data/neo4j/core/mapping/DefaultNeo4jPersistentEntity.java +++ b/src/main/java/org/springframework/data/neo4j/core/mapping/DefaultNeo4jPersistentEntity.java @@ -627,4 +627,11 @@ final class DefaultNeo4jPersistentEntity extends BasicPersistentEntity entityDescription, List labels) { + private NodeDescriptionAndLabels computeConcreteNodeDescription(NodeDescription entityDescription, @Nullable List labels) { boolean isConcreteClassThatFulfillsEverything = !Modifier.isAbstract(entityDescription.getUnderlyingClass().getModifiers()) && entityDescription.getStaticLabels().containsAll(labels); @@ -139,9 +139,9 @@ final class NodeDescriptionStore { int unmatchedLabelsCount = 0; List matchingLabels = new ArrayList<>(); - for (String staticLabel : staticLabels) { - if (labels.contains(staticLabel)) { - matchingLabels.add(staticLabel); + for (String label : labels) { + if (staticLabels.contains(label)) { + matchingLabels.add(label); } else { unmatchedLabelsCount++; } diff --git a/src/test/java/org/springframework/data/neo4j/integration/issues/IssuesIT.java b/src/test/java/org/springframework/data/neo4j/integration/issues/IssuesIT.java index 38af06af2..70941baa2 100644 --- a/src/test/java/org/springframework/data/neo4j/integration/issues/IssuesIT.java +++ b/src/test/java/org/springframework/data/neo4j/integration/issues/IssuesIT.java @@ -28,6 +28,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Optional; +import java.util.Set; import java.util.stream.Collectors; import org.assertj.core.api.InstanceOfAssertFactories; @@ -147,6 +148,9 @@ import org.springframework.data.neo4j.integration.issues.gh2819.GH2819Model; import org.springframework.data.neo4j.integration.issues.gh2819.GH2819Repository; import org.springframework.data.neo4j.integration.issues.gh2858.GH2858; import org.springframework.data.neo4j.integration.issues.gh2858.GH2858Repository; +import org.springframework.data.neo4j.integration.issues.gh2886.Apple; +import org.springframework.data.neo4j.integration.issues.gh2886.FruitRepository; +import org.springframework.data.neo4j.integration.issues.gh2886.Orange; import org.springframework.data.neo4j.integration.issues.qbe.A; import org.springframework.data.neo4j.integration.issues.qbe.ARepository; import org.springframework.data.neo4j.integration.issues.qbe.B; @@ -1162,6 +1166,32 @@ class IssuesIT extends TestBase { } + @Test + @Tag("GH-2886") + void dynamicLabels(@Autowired FruitRepository repository) { + + var f1 = new Apple(); + f1.setVolume(1.0); + f1.setColor("Red"); + f1.setLabels(Set.of("X")); + + var f2 = new Apple(); + f2.setColor("Blue"); + + var f3 = new Orange(); + f2.setVolume(3.0); + f3.setColor("Red"); + f3.setLabels(Set.of("Y")); + + var f4 = new Orange(); + f4.setColor("Yellow"); + + repository.saveAll(List.of(f1, f2, f3, f4)); + + var fruits = repository.findAllFruits(); + assertThat(fruits).allMatch(f -> f instanceof Apple || f instanceof Orange); + } + @Configuration @EnableTransactionManagement @EnableNeo4jRepositories(namedQueriesLocation = "more-custom-queries.properties") diff --git a/src/test/java/org/springframework/data/neo4j/integration/issues/gh2886/Apple.java b/src/test/java/org/springframework/data/neo4j/integration/issues/gh2886/Apple.java new file mode 100644 index 000000000..8734ef33a --- /dev/null +++ b/src/test/java/org/springframework/data/neo4j/integration/issues/gh2886/Apple.java @@ -0,0 +1,25 @@ +/* + * Copyright 2011-2024 the original author or 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 + * + * https://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 org.springframework.data.neo4j.integration.issues.gh2886; + +import org.springframework.data.neo4j.core.schema.Node; + +/** + * GH-2886 + */ +@Node(primaryLabel = "Apple") +public class Apple extends MagicalFruit { +} diff --git a/src/test/java/org/springframework/data/neo4j/integration/issues/gh2886/Fruit.java b/src/test/java/org/springframework/data/neo4j/integration/issues/gh2886/Fruit.java new file mode 100644 index 000000000..56be5cf54 --- /dev/null +++ b/src/test/java/org/springframework/data/neo4j/integration/issues/gh2886/Fruit.java @@ -0,0 +1,51 @@ +/* + * Copyright 2011-2024 the original author or 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 + * + * https://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 org.springframework.data.neo4j.integration.issues.gh2886; + +import java.util.Set; + +import org.springframework.data.neo4j.core.schema.DynamicLabels; +import org.springframework.data.neo4j.core.schema.Id; +import org.springframework.data.neo4j.core.schema.Node; + +/** + * GH-2886 + */ +@Node(primaryLabel = "Fruit") +public abstract class Fruit { + + @Id + protected String id; + + @DynamicLabels + protected Set labels = Set.of(); + + public String getId() { + return this.id; + } + + public Set getLabels() { + return this.labels; + } + + public void setId(String id) { + this.id = id; + } + + public void setLabels(Set labels) { + this.labels = labels; + } +} diff --git a/src/test/java/org/springframework/data/neo4j/integration/issues/gh2886/FruitRepository.java b/src/test/java/org/springframework/data/neo4j/integration/issues/gh2886/FruitRepository.java new file mode 100644 index 000000000..dff4f612a --- /dev/null +++ b/src/test/java/org/springframework/data/neo4j/integration/issues/gh2886/FruitRepository.java @@ -0,0 +1,31 @@ +/* + * Copyright 2011-2024 the original author or 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 + * + * https://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 org.springframework.data.neo4j.integration.issues.gh2886; + +import java.util.List; + +import org.springframework.data.neo4j.repository.Neo4jRepository; +import org.springframework.data.neo4j.repository.query.Query; +import org.springframework.stereotype.Repository; + +/** + * GH-2886 + */ +@Repository +public interface FruitRepository extends Neo4jRepository { + @Query("MATCH (f:Fruit) RETURN f") + List findAllFruits(); +} diff --git a/src/test/java/org/springframework/data/neo4j/integration/issues/gh2886/MagicalFruit.java b/src/test/java/org/springframework/data/neo4j/integration/issues/gh2886/MagicalFruit.java new file mode 100644 index 000000000..3e462ea1c --- /dev/null +++ b/src/test/java/org/springframework/data/neo4j/integration/issues/gh2886/MagicalFruit.java @@ -0,0 +1,45 @@ +/* + * Copyright 2011-2024 the original author or 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 + * + * https://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 org.springframework.data.neo4j.integration.issues.gh2886; + +import org.springframework.data.neo4j.core.schema.Node; + +/** + * GH-2886 + */ +@Node(primaryLabel = "MagicalFruit") +public class MagicalFruit extends Fruit { + + private double volume; + + private String color; + + public double getVolume() { + return this.volume; + } + + public String getColor() { + return this.color; + } + + public void setVolume(double volume) { + this.volume = volume; + } + + public void setColor(String color) { + this.color = color; + } +} diff --git a/src/test/java/org/springframework/data/neo4j/integration/issues/gh2886/Orange.java b/src/test/java/org/springframework/data/neo4j/integration/issues/gh2886/Orange.java new file mode 100644 index 000000000..1ba826583 --- /dev/null +++ b/src/test/java/org/springframework/data/neo4j/integration/issues/gh2886/Orange.java @@ -0,0 +1,25 @@ +/* + * Copyright 2011-2024 the original author or 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 + * + * https://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 org.springframework.data.neo4j.integration.issues.gh2886; + +import org.springframework.data.neo4j.core.schema.Node; + +/** + * GH-2886 + */ +@Node(primaryLabel = "Orange") +public class Orange extends MagicalFruit { +}