Skip to content

Commit 9f13e54

Browse files
christophstroblmp911de
authored andcommitted
Add support for Value Expressions.
We now support Value Expressions such as `#{1+1}-${spring.application.name:fallback-value}` that are composed of SpEL expressions, literals and Property Placeholders. See #2369 Original pull request: #3036
1 parent 5ec3c60 commit 9f13e54

12 files changed

+904
-5
lines changed

src/main/java/org/springframework/data/mapping/context/AbstractMappingContext.java

+47-1
Original file line numberDiff line numberDiff line change
@@ -40,15 +40,19 @@
4040
import org.springframework.context.ApplicationContextAware;
4141
import org.springframework.context.ApplicationEventPublisher;
4242
import org.springframework.context.ApplicationEventPublisherAware;
43+
import org.springframework.context.EnvironmentAware;
4344
import org.springframework.core.KotlinDetector;
4445
import org.springframework.core.NativeDetector;
46+
import org.springframework.core.env.Environment;
47+
import org.springframework.core.env.StandardEnvironment;
4548
import org.springframework.data.domain.ManagedTypes;
4649
import org.springframework.data.mapping.MappingException;
4750
import org.springframework.data.mapping.PersistentEntity;
4851
import org.springframework.data.mapping.PersistentProperty;
4952
import org.springframework.data.mapping.PersistentPropertyPath;
5053
import org.springframework.data.mapping.PersistentPropertyPaths;
5154
import org.springframework.data.mapping.PropertyPath;
55+
import org.springframework.data.mapping.model.AbstractPersistentProperty;
5256
import org.springframework.data.mapping.model.BeanWrapperPropertyAccessorFactory;
5357
import org.springframework.data.mapping.model.ClassGeneratingPropertyAccessorFactory;
5458
import org.springframework.data.mapping.model.EntityInstantiators;
@@ -59,6 +63,7 @@
5963
import org.springframework.data.mapping.model.SimpleTypeHolder;
6064
import org.springframework.data.spel.EvaluationContextProvider;
6165
import org.springframework.data.spel.ExtensionAwareEvaluationContextProvider;
66+
import org.springframework.data.support.EnvironmentAccessor;
6267
import org.springframework.data.util.KotlinReflectionUtils;
6368
import org.springframework.data.util.NullableWrapperConverters;
6469
import org.springframework.data.util.Optionals;
@@ -89,7 +94,7 @@
8994
* @author Christoph Strobl
9095
*/
9196
public abstract class AbstractMappingContext<E extends MutablePersistentEntity<?, P>, P extends PersistentProperty<P>>
92-
implements MappingContext<E, P>, ApplicationEventPublisherAware, ApplicationContextAware, InitializingBean {
97+
implements MappingContext<E, P>, ApplicationEventPublisherAware, ApplicationContextAware, InitializingBean, EnvironmentAware {
9398

9499
private static final Log LOGGER = LogFactory.getLog(MappingContext.class);
95100

@@ -100,6 +105,7 @@ public abstract class AbstractMappingContext<E extends MutablePersistentEntity<?
100105

101106
private @Nullable ApplicationEventPublisher applicationEventPublisher;
102107
private EvaluationContextProvider evaluationContextProvider = EvaluationContextProvider.DEFAULT;
108+
private @Nullable EnvironmentAccessor environmentAccessor;
103109

104110
private ManagedTypes managedTypes = ManagedTypes.empty();
105111

@@ -138,6 +144,10 @@ public void setApplicationContext(ApplicationContext applicationContext) throws
138144
}
139145
}
140146

147+
public void setEnvironment(Environment environment) {
148+
this.environmentAccessor = new DelegatingEnvironmentAccessor(environment);
149+
}
150+
141151
/**
142152
* Sets the {@link Set} of types to populate the context initially.
143153
*
@@ -406,6 +416,7 @@ private E doAddPersistentEntity(TypeInformation<?> typeInformation) {
406416

407417
E entity = createPersistentEntity(userTypeInformation);
408418
entity.setEvaluationContextProvider(evaluationContextProvider);
419+
entity.setEnvironmentAccessor(environmentAccessor);
409420

410421
// Eagerly cache the entity as we might have to find it during recursive lookups.
411422
persistentEntities.put(userTypeInformation, Optional.of(entity));
@@ -477,6 +488,10 @@ public Collection<TypeInformation<?>> getManagedTypes() {
477488

478489
@Override
479490
public void afterPropertiesSet() {
491+
492+
if(this.environmentAccessor == null) {
493+
this.environmentAccessor = new DelegatingEnvironmentAccessor(new StandardEnvironment());
494+
}
480495
initialize();
481496
}
482497

@@ -579,6 +594,9 @@ private void createAndRegisterProperty(Property input) {
579594
return;
580595
}
581596

597+
if(property instanceof AbstractPersistentProperty<?> pp) {
598+
pp.setEnvironmentAccessor(environmentAccessor);
599+
}
582600
entity.addPersistentProperty(property);
583601

584602
if (property.isAssociation()) {
@@ -776,4 +794,32 @@ public boolean matches(String name, Class<?> type) {
776794
}
777795
}
778796
}
797+
798+
/**
799+
* @author Christoph Strobl
800+
* @since 3.3
801+
*/
802+
public static class DelegatingEnvironmentAccessor implements EnvironmentAccessor {
803+
804+
private final Environment environment;
805+
806+
static EnvironmentAccessor standard() {
807+
return new DelegatingEnvironmentAccessor(new StandardEnvironment());
808+
}
809+
810+
public DelegatingEnvironmentAccessor(Environment environment) {
811+
this.environment = environment;
812+
}
813+
814+
@Nullable
815+
@Override
816+
public String getProperty(String key) {
817+
return environment.getProperty(key);
818+
}
819+
820+
@Override
821+
public String resolvePlaceholders(String text) {
822+
return environment.resolvePlaceholders(text);
823+
}
824+
}
779825
}

src/main/java/org/springframework/data/mapping/model/AbstractPersistentProperty.java

+12
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
import org.springframework.data.mapping.Association;
2828
import org.springframework.data.mapping.PersistentEntity;
2929
import org.springframework.data.mapping.PersistentProperty;
30+
import org.springframework.data.support.EnvironmentAccessor;
3031
import org.springframework.data.util.KotlinReflectionUtils;
3132
import org.springframework.data.util.Lazy;
3233
import org.springframework.data.util.ReflectionUtils;
@@ -74,6 +75,9 @@ public abstract class AbstractPersistentProperty<P extends PersistentProperty<P>
7475
private final Lazy<Boolean> readable;
7576
private final boolean immutable;
7677

78+
79+
private @Nullable EnvironmentAccessor environmentAccessor;
80+
7781
public AbstractPersistentProperty(Property property, PersistentEntity<?, P> owner,
7882
SimpleTypeHolder simpleTypeHolder) {
7983

@@ -306,6 +310,14 @@ protected TypeInformation<?> getActualTypeInformation() {
306310
return targetType == null ? information.getRequiredActualType() : targetType;
307311
}
308312

313+
protected EnvironmentAccessor getEnvironmentAccessor() {
314+
return environmentAccessor;
315+
}
316+
317+
public void setEnvironmentAccessor(EnvironmentAccessor environmentAccessor) {
318+
this.environmentAccessor = environmentAccessor;
319+
}
320+
309321
@Override
310322
public boolean equals(@Nullable Object obj) {
311323

src/main/java/org/springframework/data/mapping/model/AnnotationBasedPersistentProperty.java

+1
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
import org.springframework.data.mapping.MappingException;
3838
import org.springframework.data.mapping.PersistentEntity;
3939
import org.springframework.data.mapping.PersistentProperty;
40+
import org.springframework.data.support.EnvironmentAccessor;
4041
import org.springframework.data.util.ClassTypeInformation;
4142
import org.springframework.data.util.Lazy;
4243
import org.springframework.data.util.Optionals;

src/main/java/org/springframework/data/mapping/model/BasicPersistentEntity.java

+20-4
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
import org.springframework.data.mapping.*;
3737
import org.springframework.data.spel.EvaluationContextProvider;
3838
import org.springframework.data.spel.ExpressionDependencies;
39+
import org.springframework.data.support.EnvironmentAccessor;
3940
import org.springframework.data.support.IsNewStrategy;
4041
import org.springframework.data.support.PersistableIsNewStrategy;
4142
import org.springframework.data.util.Lazy;
@@ -79,6 +80,7 @@ public class BasicPersistentEntity<T, P extends PersistentProperty<P>> implement
7980
private @Nullable P versionProperty;
8081
private PersistentPropertyAccessorFactory propertyAccessorFactory;
8182
private EvaluationContextProvider evaluationContextProvider = EvaluationContextProvider.DEFAULT;
83+
private @Nullable EnvironmentAccessor environmentAccessor;
8284

8385
private final Lazy<Alias> typeAlias;
8486
private final Lazy<IsNewStrategy> isNewStrategy;
@@ -205,10 +207,8 @@ public void addPersistentProperty(P property) {
205207
if (versionProperty != null) {
206208

207209
throw new MappingException(
208-
String.format(
209-
"Attempt to add version property %s but already have property %s registered "
210-
+ "as version; Check your mapping configuration",
211-
property.getField(), versionProperty.getField()));
210+
String.format("Attempt to add version property %s but already have property %s registered "
211+
+ "as version; Check your mapping configuration", property.getField(), versionProperty.getField()));
212212
}
213213

214214
this.versionProperty = property;
@@ -220,6 +220,11 @@ public void setEvaluationContextProvider(EvaluationContextProvider provider) {
220220
this.evaluationContextProvider = provider;
221221
}
222222

223+
@Override
224+
public void setEnvironmentAccessor(EnvironmentAccessor accessor) {
225+
this.environmentAccessor = accessor;
226+
}
227+
223228
/**
224229
* Returns the given property if it is a better candidate for the id property than the current id property.
225230
*
@@ -443,6 +448,17 @@ protected EvaluationContext getEvaluationContext(Object rootObject, ExpressionDe
443448
return evaluationContextProvider.getEvaluationContext(rootObject, dependencies);
444449
}
445450

451+
/**
452+
* Obtain the {@link EnvironmentAccessor} providing access to the current
453+
* {@link org.springframework.core.env.Environment}.
454+
*
455+
* @return never {@literal null}.
456+
* @since 3.3
457+
*/
458+
protected EnvironmentAccessor getEnvironmentAccessor() {
459+
return environmentAccessor;
460+
}
461+
446462
/**
447463
* Returns the default {@link IsNewStrategy} to be used. Will be a {@link PersistentEntityIsNewStrategy} by default.
448464
* Note, that this strategy only gets used if the entity doesn't implement {@link Persistable} as this indicates the

src/main/java/org/springframework/data/mapping/model/MutablePersistentEntity.java

+9
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
import org.springframework.data.mapping.PersistentProperty;
2222
import org.springframework.data.mapping.PersistentPropertyAccessor;
2323
import org.springframework.data.spel.EvaluationContextProvider;
24+
import org.springframework.data.support.EnvironmentAccessor;
2425

2526
/**
2627
* Interface capturing mutator methods for {@link PersistentEntity}s.
@@ -66,4 +67,12 @@ public interface MutablePersistentEntity<T, P extends PersistentProperty<P>> ext
6667
* @param provider must not be {@literal null}.
6768
*/
6869
void setEvaluationContextProvider(EvaluationContextProvider provider);
70+
71+
/**
72+
* Sets the {@link EnvironmentAccessor} to be used by the entity.
73+
*
74+
* @param accessor must not be {@literal null}.
75+
* @since 3.3
76+
*/
77+
void setEnvironmentAccessor(EnvironmentAccessor accessor);
6978
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
/*
2+
* Copyright 2023 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.data.support;
18+
19+
import org.springframework.lang.Nullable;
20+
21+
/**
22+
* @author Christoph Strobl
23+
* @since 3.3
24+
*/
25+
public interface EnvironmentAccessor extends PlaceholderResolver {
26+
27+
@Nullable
28+
String getProperty(String key);
29+
30+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
/*
2+
* Copyright 2023 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.support;
17+
18+
/**
19+
* @author Christoph Strobl
20+
* @since 3.3
21+
*/
22+
public interface PlaceholderResolver {
23+
24+
String resolvePlaceholders(String text);
25+
}

0 commit comments

Comments
 (0)