Skip to content

Commit 2d53fdc

Browse files
mp911derstoyanchev
authored andcommitted
Spring Data repositories that support Querydsl
Spring Data repositories that support Querydsl are now supported as DataFetchers returning single objects and iterables including projection support. See gh-59
1 parent ab99dc2 commit 2d53fdc

File tree

13 files changed

+1050
-5
lines changed

13 files changed

+1050
-5
lines changed

build.gradle

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,12 +30,13 @@ configure(moduleProjects) {
3030
sourceCompatibility = JavaVersion.VERSION_1_8
3131
targetCompatibility = JavaVersion.VERSION_1_8
3232
}
33-
33+
3434
dependencyManagement {
3535
imports {
3636
mavenBom "com.fasterxml.jackson:jackson-bom:2.12.3"
3737
mavenBom "io.projectreactor:reactor-bom:2020.0.7"
3838
mavenBom "org.springframework:spring-framework-bom:5.3.7"
39+
mavenBom "org.springframework.data:spring-data-bom:2021.0.1"
3940
mavenBom "org.junit:junit-bom:5.7.2"
4041
}
4142
dependencies {

samples/webmvc-http/build.gradle

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,20 @@ dependencies {
1818
testImplementation project(':spring-graphql-test')
1919
testImplementation 'org.springframework:spring-webflux'
2020
testImplementation 'org.springframework.boot:spring-boot-starter-test'
21+
22+
implementation(
23+
"com.querydsl:querydsl-core:4.4.0",
24+
"com.querydsl:querydsl-jpa:4.4.0"
25+
)
26+
annotationProcessor "com.querydsl:querydsl-apt:4.4.0:jpa",
27+
"org.hibernate.javax.persistence:hibernate-jpa-2.1-api:1.0.2.Final",
28+
"javax.annotation:javax.annotation-api:1.3.2"
29+
}
30+
31+
compileJava {
32+
options.annotationProcessorPath = configurations.annotationProcessor
2133
}
34+
2235
test {
2336
useJUnitPlatform()
24-
}
37+
}
Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
package io.spring.sample.graphql.repository;
22

3+
import org.springframework.data.querydsl.QuerydslPredicateExecutor;
34
import org.springframework.data.repository.CrudRepository;
45

5-
public interface ArtifactRepositories extends CrudRepository<ArtifactRepository, String> {
6+
public interface ArtifactRepositories extends CrudRepository<ArtifactRepository, String>, QuerydslPredicateExecutor<ArtifactRepository> {
67

78
}

samples/webmvc-http/src/main/java/io/spring/sample/graphql/repository/ArtifactRepositoryDataWiring.java

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
package io.spring.sample.graphql.repository;
22

33
import graphql.schema.idl.RuntimeWiring;
4+
45
import org.springframework.graphql.boot.RuntimeWiringCustomizer;
6+
import org.springframework.graphql.data.QuerydslDataFetcher;
57
import org.springframework.stereotype.Component;
68

79
@Component
@@ -16,8 +18,10 @@ public ArtifactRepositoryDataWiring(ArtifactRepositories repositories) {
1618
@Override
1719
public void customize(RuntimeWiring.Builder builder) {
1820
builder.type("Query",
19-
typeWiring -> typeWiring.dataFetcher("artifactRepositories", env -> this.repositories.findAll())
20-
.dataFetcher("artifactRepository", env -> this.repositories.findById(env.getArgument("id"))));
21+
typeWiring -> typeWiring.dataFetcher("artifactRepositories", QuerydslDataFetcher
22+
.builder(repositories).many())
23+
.dataFetcher("artifactRepository", QuerydslDataFetcher
24+
.builder(repositories).single()));
2125
}
2226

2327
}

spring-graphql/build.gradle

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,19 @@ dependencies {
1111
compileOnly 'org.springframework:spring-websocket'
1212
compileOnly 'javax.servlet:javax.servlet-api:4.0.1'
1313

14+
compileOnly 'com.querydsl:querydsl-core:4.4.0'
15+
compileOnly 'org.springframework.data:spring-data-commons'
16+
1417
testImplementation 'org.junit.jupiter:junit-jupiter'
1518
testImplementation 'org.assertj:assertj-core'
19+
testImplementation 'org.mockito:mockito-core:3.11.1'
1620
testImplementation 'io.projectreactor:reactor-test'
1721
testImplementation 'org.springframework:spring-webflux'
1822
testImplementation 'org.springframework:spring-webmvc'
1923
testImplementation 'org.springframework:spring-websocket'
2024
testImplementation 'org.springframework:spring-test'
25+
testImplementation 'org.springframework.data:spring-data-commons'
26+
testImplementation 'com.querydsl:querydsl-core:4.4.0'
2127
testImplementation 'javax.servlet:javax.servlet-api:4.0.1'
2228
testImplementation 'com.fasterxml.jackson.core:jackson-databind'
2329

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
/*
2+
* Copyright 2002-2021 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.graphql.data;
18+
19+
import org.springframework.core.convert.converter.Converter;
20+
import org.springframework.data.mapping.PersistentEntity;
21+
import org.springframework.data.mapping.PersistentProperty;
22+
import org.springframework.data.mapping.PersistentPropertyAccessor;
23+
import org.springframework.data.mapping.PreferredConstructor;
24+
import org.springframework.data.mapping.PreferredConstructor.Parameter;
25+
import org.springframework.data.mapping.SimplePropertyHandler;
26+
import org.springframework.data.mapping.context.MappingContext;
27+
import org.springframework.data.mapping.model.EntityInstantiator;
28+
import org.springframework.data.mapping.model.EntityInstantiators;
29+
import org.springframework.data.mapping.model.ParameterValueProvider;
30+
31+
/**
32+
* {@link Converter} to instantiate DTOs from fully equipped domain objects.
33+
*
34+
* @author Mark Paluch
35+
* @since 1.0.0
36+
*/
37+
class DtoInstantiatingConverter<T> implements Converter<Object, T> {
38+
39+
private final Class<T> targetType;
40+
41+
private final MappingContext<? extends PersistentEntity<?, ?>, ? extends PersistentProperty<?>> context;
42+
43+
private final EntityInstantiator instantiator;
44+
45+
/**
46+
* Create a new {@link Converter} to instantiate DTOs.
47+
* @param dtoType target type
48+
* @param context mapping context to be used
49+
* @param entityInstantiators the instantiators to use for object creation
50+
*/
51+
public DtoInstantiatingConverter(Class<T> dtoType,
52+
MappingContext<? extends PersistentEntity<?, ?>, ? extends PersistentProperty<?>> context,
53+
EntityInstantiators entityInstantiators) {
54+
this.targetType = dtoType;
55+
this.context = context;
56+
this.instantiator = entityInstantiators
57+
.getInstantiatorFor(context.getRequiredPersistentEntity(dtoType));
58+
}
59+
60+
@SuppressWarnings("unchecked")
61+
@Override
62+
public T convert(Object source) {
63+
64+
if (targetType.isInterface()) {
65+
return (T) source;
66+
}
67+
68+
PersistentEntity<?, ?> sourceEntity = context
69+
.getRequiredPersistentEntity(source.getClass());
70+
71+
PersistentPropertyAccessor<?> sourceAccessor = sourceEntity
72+
.getPropertyAccessor(source);
73+
PersistentEntity<?, ?> targetEntity = context
74+
.getRequiredPersistentEntity(targetType);
75+
PreferredConstructor<?, ? extends PersistentProperty<?>> constructor = targetEntity
76+
.getPersistenceConstructor();
77+
78+
@SuppressWarnings({"rawtypes", "unchecked"})
79+
Object dto = instantiator
80+
.createInstance(targetEntity, new ParameterValueProvider() {
81+
82+
@Override
83+
public Object getParameterValue(Parameter parameter) {
84+
return sourceAccessor.getProperty(sourceEntity
85+
.getRequiredPersistentProperty(parameter.getName()));
86+
}
87+
});
88+
89+
PersistentPropertyAccessor<?> dtoAccessor = targetEntity
90+
.getPropertyAccessor(dto);
91+
92+
targetEntity.doWithProperties((SimplePropertyHandler) property -> {
93+
94+
if (constructor.isConstructorParameter(property)) {
95+
return;
96+
}
97+
98+
dtoAccessor.setProperty(property,
99+
sourceAccessor.getProperty(sourceEntity
100+
.getRequiredPersistentProperty(property.getName())));
101+
});
102+
103+
return (T) dto;
104+
}
105+
106+
}
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
/*
2+
* Copyright 2002-2021 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.graphql.data;
18+
19+
import org.springframework.data.mapping.Association;
20+
import org.springframework.data.mapping.PersistentEntity;
21+
import org.springframework.data.mapping.context.AbstractMappingContext;
22+
import org.springframework.data.mapping.model.AnnotationBasedPersistentProperty;
23+
import org.springframework.data.mapping.model.BasicPersistentEntity;
24+
import org.springframework.data.mapping.model.Property;
25+
import org.springframework.data.mapping.model.SimpleTypeHolder;
26+
import org.springframework.data.util.TypeInformation;
27+
28+
/**
29+
* Lightweight {@link org.springframework.data.mapping.context.MappingContext}
30+
* to provide class metadata for entity to DTO mapping.
31+
*
32+
* @author Mark Paluch
33+
* @since 1.0.0
34+
*/
35+
class DtoMappingContext extends AbstractMappingContext<DtoMappingContext.DtoPersistentEntity<?>,
36+
DtoMappingContext.DtoPersistentProperty> {
37+
38+
@Override
39+
protected boolean shouldCreatePersistentEntityFor(TypeInformation<?> type) {
40+
// No Java std lib type introspection to not interfere with encapsulation.
41+
// We do not want to get into the business of materializing Java types.
42+
if (type.getType().getName().startsWith("java.") || type.getType().getName()
43+
.startsWith("javax.")) {
44+
return false;
45+
}
46+
return super.shouldCreatePersistentEntityFor(type);
47+
}
48+
49+
@Override
50+
protected <T> DtoPersistentEntity<?> createPersistentEntity(TypeInformation<T> typeInformation) {
51+
return new DtoPersistentEntity<>(typeInformation);
52+
}
53+
54+
@Override
55+
protected DtoPersistentProperty createPersistentProperty(Property property, DtoPersistentEntity<?> owner,
56+
SimpleTypeHolder simpleTypeHolder) {
57+
return new DtoPersistentProperty(property, owner, simpleTypeHolder);
58+
}
59+
60+
static class DtoPersistentEntity<T> extends BasicPersistentEntity<T, DtoPersistentProperty> {
61+
62+
public DtoPersistentEntity(TypeInformation<T> information) {
63+
super(information);
64+
}
65+
66+
}
67+
68+
static class DtoPersistentProperty extends AnnotationBasedPersistentProperty<DtoPersistentProperty> {
69+
70+
public DtoPersistentProperty(Property property, PersistentEntity<?, DtoPersistentProperty> owner,
71+
SimpleTypeHolder simpleTypeHolder) {
72+
super(property, owner, simpleTypeHolder);
73+
}
74+
75+
@Override
76+
protected Association<DtoPersistentProperty> createAssociation() {
77+
return null;
78+
}
79+
80+
}
81+
82+
}

0 commit comments

Comments
 (0)