Skip to content

Commit 557465b

Browse files
committed
Introduce standard DtoInstantiatingConverter.
Move simple Spring Converter implementation that allow to create DTOs from a source object previously copied amongst a variety of store modules. Issue #2476.
1 parent ac9f99f commit 557465b

File tree

1 file changed

+112
-0
lines changed

1 file changed

+112
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
/*
2+
* Copyright 2022 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+
package org.springframework.data.convert;
17+
18+
import org.springframework.core.convert.converter.Converter;
19+
import org.springframework.data.mapping.Parameter;
20+
import org.springframework.data.mapping.PersistentEntity;
21+
import org.springframework.data.mapping.PersistentProperty;
22+
import org.springframework.data.mapping.SimplePropertyHandler;
23+
import org.springframework.data.mapping.context.MappingContext;
24+
import org.springframework.data.mapping.model.EntityInstantiator;
25+
import org.springframework.data.mapping.model.EntityInstantiators;
26+
import org.springframework.data.mapping.model.ParameterValueProvider;
27+
import org.springframework.lang.NonNull;
28+
import org.springframework.lang.Nullable;
29+
import org.springframework.util.Assert;
30+
31+
/**
32+
* Spring {@link Converter} to create instances of the given DTO type from the source value handed into the conversion.
33+
*
34+
* @author Mark Paluch
35+
* @author Oliver Drotbohm
36+
* @since 2.7
37+
*/
38+
public class DtoInstantiatingConverter implements Converter<Object, Object> {
39+
40+
private final Class<?> targetType;
41+
private final MappingContext<? extends PersistentEntity<?, ?>, ? extends PersistentProperty<?>> context;
42+
private final EntityInstantiator instantiator;
43+
44+
/**
45+
* Create a new {@link Converter} to instantiate DTOs.
46+
*
47+
* @param dtoType must not be {@literal null}.
48+
* @param context must not be {@literal null}.
49+
* @param instantiators must not be {@literal null}.
50+
*/
51+
public DtoInstantiatingConverter(Class<?> dtoType,
52+
MappingContext<? extends PersistentEntity<?, ?>, ? extends PersistentProperty<?>> context,
53+
EntityInstantiators instantiators) {
54+
55+
Assert.notNull(dtoType, "DTO type must not be null!");
56+
Assert.notNull(context, "MappingContext must not be null!");
57+
Assert.notNull(instantiators, "EntityInstantiators must not be null!");
58+
59+
this.targetType = dtoType;
60+
this.context = context;
61+
this.instantiator = instantiators.getInstantiatorFor(context.getRequiredPersistentEntity(dtoType));
62+
}
63+
64+
/*
65+
* (non-Javadoc)
66+
* @see org.springframework.core.convert.converter.Converter#convert(java.lang.Object)
67+
*/
68+
@NonNull
69+
@Override
70+
public Object convert(Object source) {
71+
72+
if (targetType.isInterface()) {
73+
return source;
74+
}
75+
76+
var sourceEntity = context.getRequiredPersistentEntity(source.getClass());
77+
var sourceAccessor = sourceEntity.getPropertyAccessor(source);
78+
var targetEntity = context.getRequiredPersistentEntity(targetType);
79+
80+
@SuppressWarnings({ "rawtypes", "unchecked" })
81+
var dto = instantiator.createInstance(targetEntity, new ParameterValueProvider() {
82+
83+
@Override
84+
@Nullable
85+
public Object getParameterValue(Parameter parameter) {
86+
87+
var name = parameter.getName();
88+
89+
if (name == null) {
90+
throw new IllegalArgumentException(String.format("Parameter %s does not have a name", parameter));
91+
}
92+
93+
return sourceAccessor.getProperty(sourceEntity.getRequiredPersistentProperty(name));
94+
}
95+
});
96+
97+
var targetAccessor = targetEntity.getPropertyAccessor(dto);
98+
var creator = targetEntity.getInstanceCreatorMetadata();
99+
100+
targetEntity.doWithProperties((SimplePropertyHandler) property -> {
101+
102+
if ((creator != null) && creator.isCreatorParameter(property)) {
103+
return;
104+
}
105+
106+
targetAccessor.setProperty(property,
107+
sourceAccessor.getProperty(sourceEntity.getRequiredPersistentProperty(property.getName())));
108+
});
109+
110+
return dto;
111+
}
112+
}

0 commit comments

Comments
 (0)