Refine KotlinDetector usages and implementation

This commit refines KotlinDetector usages and implementation in order
to remove preliminary KotlinDetector#isKotlinReflectPresent invocations
and to ensure that KotlinDetector methods are implemented safely and
efficiently for such use case.

Closes gh-34275
This commit is contained in:
Sébastien Deleuze 2025-01-17 16:21:50 +01:00
parent ffd7b93dde
commit 1763334180
15 changed files with 56 additions and 66 deletions

View File

@ -186,7 +186,7 @@ public abstract class BeanUtils {
Assert.notNull(ctor, "Constructor must not be null"); Assert.notNull(ctor, "Constructor must not be null");
try { try {
ReflectionUtils.makeAccessible(ctor); ReflectionUtils.makeAccessible(ctor);
if (KotlinDetector.isKotlinReflectPresent() && KotlinDetector.isKotlinType(ctor.getDeclaringClass())) { if (KotlinDetector.isKotlinType(ctor.getDeclaringClass())) {
return KotlinDelegate.instantiateClass(ctor, args); return KotlinDelegate.instantiateClass(ctor, args);
} }
else { else {
@ -279,7 +279,7 @@ public abstract class BeanUtils {
*/ */
public static <T> @Nullable Constructor<T> findPrimaryConstructor(Class<T> clazz) { public static <T> @Nullable Constructor<T> findPrimaryConstructor(Class<T> clazz) {
Assert.notNull(clazz, "Class must not be null"); Assert.notNull(clazz, "Class must not be null");
if (KotlinDetector.isKotlinReflectPresent() && KotlinDetector.isKotlinType(clazz)) { if (KotlinDetector.isKotlinType(clazz)) {
return KotlinDelegate.findPrimaryConstructor(clazz); return KotlinDelegate.findPrimaryConstructor(clazz);
} }
if (clazz.isRecord()) { if (clazz.isRecord()) {

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2024 the original author or authors. * Copyright 2002-2025 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -160,7 +160,7 @@ public class InstanceSupplierCodeGenerator {
registeredBean.getBeanName(), constructor, registeredBean.getBeanClass()); registeredBean.getBeanName(), constructor, registeredBean.getBeanClass());
Class<?> publicType = descriptor.publicType(); Class<?> publicType = descriptor.publicType();
if (KotlinDetector.isKotlinReflectPresent() && KotlinDelegate.hasConstructorWithOptionalParameter(publicType)) { if (KotlinDetector.isKotlinType(publicType) && KotlinDelegate.hasConstructorWithOptionalParameter(publicType)) {
return generateCodeForInaccessibleConstructor(descriptor, return generateCodeForInaccessibleConstructor(descriptor,
hints -> hints.registerType(publicType, MemberCategory.INVOKE_DECLARED_CONSTRUCTORS)); hints -> hints.registerType(publicType, MemberCategory.INVOKE_DECLARED_CONSTRUCTORS));
} }
@ -408,13 +408,11 @@ public class InstanceSupplierCodeGenerator {
private static class KotlinDelegate { private static class KotlinDelegate {
public static boolean hasConstructorWithOptionalParameter(Class<?> beanClass) { public static boolean hasConstructorWithOptionalParameter(Class<?> beanClass) {
if (KotlinDetector.isKotlinType(beanClass)) { KClass<?> kClass = JvmClassMappingKt.getKotlinClass(beanClass);
KClass<?> kClass = JvmClassMappingKt.getKotlinClass(beanClass); for (KFunction<?> constructor : kClass.getConstructors()) {
for (KFunction<?> constructor : kClass.getConstructors()) { for (KParameter parameter : constructor.getParameters()) {
for (KParameter parameter : constructor.getParameters()) { if (parameter.isOptional()) {
if (parameter.isOptional()) { return true;
return true;
}
} }
} }
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2024 the original author or authors. * Copyright 2002-2025 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -163,9 +163,7 @@ public class DependencyDescriptor extends InjectionPoint implements Serializable
if (this.field != null) { if (this.field != null) {
return !(this.field.getType() == Optional.class || hasNullableAnnotation() || return !(this.field.getType() == Optional.class || hasNullableAnnotation() ||
(KotlinDetector.isKotlinReflectPresent() && (KotlinDetector.isKotlinType(this.field.getDeclaringClass()) && KotlinDelegate.isNullable(this.field)));
KotlinDetector.isKotlinType(this.field.getDeclaringClass()) &&
KotlinDelegate.isNullable(this.field)));
} }
else { else {
return !obtainMethodParameter().isOptional(); return !obtainMethodParameter().isOptional();

View File

@ -624,7 +624,7 @@ class ConstructorResolver {
"Invalid factory method '" + mbd.getFactoryMethodName() + "' on class [" + "Invalid factory method '" + mbd.getFactoryMethodName() + "' on class [" +
factoryClass.getName() + "]: needs to have a non-void return type!"); factoryClass.getName() + "]: needs to have a non-void return type!");
} }
else if (KotlinDetector.isKotlinPresent() && KotlinDetector.isSuspendingFunction(factoryMethodToUse)) { else if (KotlinDetector.isSuspendingFunction(factoryMethodToUse)) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName, throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Invalid factory method '" + mbd.getFactoryMethodName() + "' on class [" + "Invalid factory method '" + mbd.getFactoryMethodName() + "' on class [" +
factoryClass.getName() + "]: suspending functions are not supported!"); factoryClass.getName() + "]: suspending functions are not supported!");

View File

@ -1092,7 +1092,7 @@ public abstract class CacheAspectSupport extends AbstractCacheInvoker
() -> Mono.from(adapter.toPublisher(invokeOperation(invoker))).toFuture()))); () -> Mono.from(adapter.toPublisher(invokeOperation(invoker))).toFuture())));
} }
} }
if (KotlinDetector.isKotlinReflectPresent() && KotlinDetector.isSuspendingFunction(method)) { if (KotlinDetector.isSuspendingFunction(method)) {
return Mono.fromFuture(cache.retrieve(key, () -> { return Mono.fromFuture(cache.retrieve(key, () -> {
Mono<?> mono = ((Mono<?>) invokeOperation(invoker)); Mono<?> mono = ((Mono<?>) invokeOperation(invoker));
if (mono == null) { if (mono == null) {

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2024 the original author or authors. * Copyright 2002-2025 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -81,7 +81,7 @@ abstract class ScheduledAnnotationReactiveSupport {
* Kotlin coroutines bridge are not present at runtime * Kotlin coroutines bridge are not present at runtime
*/ */
public static boolean isReactive(Method method) { public static boolean isReactive(Method method) {
if (KotlinDetector.isKotlinPresent() && KotlinDetector.isSuspendingFunction(method)) { if (KotlinDetector.isSuspendingFunction(method)) {
// Note that suspending functions declared without args have a single Continuation // Note that suspending functions declared without args have a single Continuation
// parameter in reflective inspection // parameter in reflective inspection
Assert.isTrue(method.getParameterCount() == 1, Assert.isTrue(method.getParameterCount() == 1,
@ -138,7 +138,7 @@ abstract class ScheduledAnnotationReactiveSupport {
* to a {@code Flux} with a checkpoint String, allowing for better debugging. * to a {@code Flux} with a checkpoint String, allowing for better debugging.
*/ */
static Publisher<?> getPublisherFor(Method method, Object bean) { static Publisher<?> getPublisherFor(Method method, Object bean) {
if (KotlinDetector.isKotlinPresent() && KotlinDetector.isSuspendingFunction(method)) { if (KotlinDetector.isSuspendingFunction(method)) {
return CoroutinesUtils.invokeSuspendingFunction(method, bean, (Object[]) method.getParameters()); return CoroutinesUtils.invokeSuspendingFunction(method, bean, (Object[]) method.getParameters());
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2024 the original author or authors. * Copyright 2002-2025 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -24,7 +24,8 @@ import org.jspecify.annotations.Nullable;
import org.springframework.util.ClassUtils; import org.springframework.util.ClassUtils;
/** /**
* A common delegate for detecting Kotlin's presence and for identifying Kotlin types. * A common delegate for detecting Kotlin's presence and for identifying Kotlin types. All the methods of this class
* can be safely used without any preliminary classpath checks.
* *
* @author Juergen Hoeller * @author Juergen Hoeller
* @author Sebastien Deleuze * @author Sebastien Deleuze
@ -37,6 +38,8 @@ public abstract class KotlinDetector {
private static final @Nullable Class<? extends Annotation> kotlinJvmInline; private static final @Nullable Class<? extends Annotation> kotlinJvmInline;
private static final @Nullable Class<?> kotlinCoroutineContinuation;
// For ConstantFieldFeature compliance, otherwise could be deduced from kotlinMetadata // For ConstantFieldFeature compliance, otherwise could be deduced from kotlinMetadata
private static final boolean kotlinPresent; private static final boolean kotlinPresent;
@ -46,6 +49,7 @@ public abstract class KotlinDetector {
ClassLoader classLoader = KotlinDetector.class.getClassLoader(); ClassLoader classLoader = KotlinDetector.class.getClassLoader();
Class<?> metadata = null; Class<?> metadata = null;
Class<?> jvmInline = null; Class<?> jvmInline = null;
Class<?> coroutineContinuation = null;
try { try {
metadata = ClassUtils.forName("kotlin.Metadata", classLoader); metadata = ClassUtils.forName("kotlin.Metadata", classLoader);
try { try {
@ -54,14 +58,21 @@ public abstract class KotlinDetector {
catch (ClassNotFoundException ex) { catch (ClassNotFoundException ex) {
// JVM inline support not available // JVM inline support not available
} }
try {
coroutineContinuation = ClassUtils.forName("kotlin.coroutines.Continuation", classLoader);
}
catch (ClassNotFoundException ex) {
// Coroutines support not available
}
} }
catch (ClassNotFoundException ex) { catch (ClassNotFoundException ex) {
// Kotlin API not available - no Kotlin support // Kotlin API not available - no Kotlin support
} }
kotlinMetadata = (Class<? extends Annotation>) metadata; kotlinMetadata = (Class<? extends Annotation>) metadata;
kotlinPresent = (kotlinMetadata != null); kotlinPresent = (kotlinMetadata != null);
kotlinReflectPresent = kotlinPresent && ClassUtils.isPresent("kotlin.reflect.full.KClasses", classLoader); kotlinReflectPresent = ClassUtils.isPresent("kotlin.reflect.full.KClasses", classLoader);
kotlinJvmInline = (Class<? extends Annotation>) jvmInline; kotlinJvmInline = (Class<? extends Annotation>) jvmInline;
kotlinCoroutineContinuation = coroutineContinuation;
} }
@ -89,7 +100,7 @@ public abstract class KotlinDetector {
* as invokedynamic has become the default method for lambda generation. * as invokedynamic has become the default method for lambda generation.
*/ */
public static boolean isKotlinType(Class<?> clazz) { public static boolean isKotlinType(Class<?> clazz) {
return (kotlinMetadata != null && clazz.getDeclaredAnnotation(kotlinMetadata) != null); return (kotlinPresent && clazz.getDeclaredAnnotation(kotlinMetadata) != null);
} }
/** /**
@ -97,13 +108,11 @@ public abstract class KotlinDetector {
* @since 5.3 * @since 5.3
*/ */
public static boolean isSuspendingFunction(Method method) { public static boolean isSuspendingFunction(Method method) {
if (KotlinDetector.isKotlinType(method.getDeclaringClass())) { if (kotlinCoroutineContinuation == null) {
Class<?>[] types = method.getParameterTypes(); return false;
if (types.length > 0 && "kotlin.coroutines.Continuation".equals(types[types.length - 1].getName())) {
return true;
}
} }
return false; int parameterCount = method.getParameterCount();
return (parameterCount > 0 && method.getParameterTypes()[parameterCount - 1] == kotlinCoroutineContinuation);
} }
/** /**

View File

@ -396,9 +396,7 @@ public class MethodParameter {
*/ */
public boolean isOptional() { public boolean isOptional() {
return (getParameterType() == Optional.class || hasNullableAnnotation() || return (getParameterType() == Optional.class || hasNullableAnnotation() ||
(KotlinDetector.isKotlinReflectPresent() && (KotlinDetector.isKotlinType(getContainingClass()) && KotlinDelegate.isOptional(this)));
KotlinDetector.isKotlinType(getContainingClass()) &&
KotlinDelegate.isOptional(this)));
} }
/** /**
@ -508,8 +506,8 @@ public class MethodParameter {
if (this.parameterIndex < 0) { if (this.parameterIndex < 0) {
Method method = getMethod(); Method method = getMethod();
paramType = (method != null ? paramType = (method != null ?
(KotlinDetector.isKotlinReflectPresent() && KotlinDetector.isKotlinType(getContainingClass()) ? (KotlinDetector.isKotlinType(getContainingClass()) ?
KotlinDelegate.getGenericReturnType(method) : method.getGenericReturnType()) : void.class); KotlinDelegate.getGenericReturnType(method) : method.getGenericReturnType()) : void.class);
} }
else { else {
Type[] genericParameterTypes = this.executable.getGenericParameterTypes(); Type[] genericParameterTypes = this.executable.getGenericParameterTypes();
@ -536,7 +534,7 @@ public class MethodParameter {
if (method == null) { if (method == null) {
return void.class; return void.class;
} }
if (KotlinDetector.isKotlinReflectPresent() && KotlinDetector.isKotlinType(getContainingClass())) { if (KotlinDetector.isKotlinType(getContainingClass())) {
return KotlinDelegate.getReturnType(method); return KotlinDelegate.getReturnType(method);
} }
return method.getReturnType(); return method.getReturnType();

View File

@ -374,7 +374,7 @@ public class SpringFactoriesLoader {
T instantiate(@Nullable ArgumentResolver argumentResolver) throws Exception { T instantiate(@Nullable ArgumentResolver argumentResolver) throws Exception {
Object[] args = resolveArgs(argumentResolver); Object[] args = resolveArgs(argumentResolver);
if (isKotlinType(this.constructor.getDeclaringClass())) { if (KotlinDetector.isKotlinType(this.constructor.getDeclaringClass())) {
return KotlinDelegate.instantiate(this.constructor, args); return KotlinDelegate.instantiate(this.constructor, args);
} }
return this.constructor.newInstance(args); return this.constructor.newInstance(args);
@ -408,14 +408,10 @@ public class SpringFactoriesLoader {
} }
private static @Nullable Constructor<?> findPrimaryKotlinConstructor(Class<?> factoryImplementationClass) { private static @Nullable Constructor<?> findPrimaryKotlinConstructor(Class<?> factoryImplementationClass) {
return (isKotlinType(factoryImplementationClass) ? return (KotlinDetector.isKotlinType(factoryImplementationClass) ?
KotlinDelegate.findPrimaryConstructor(factoryImplementationClass) : null); KotlinDelegate.findPrimaryConstructor(factoryImplementationClass) : null);
} }
private static boolean isKotlinType(Class<?> factoryImplementationClass) {
return KotlinDetector.isKotlinReflectPresent() && KotlinDetector.isKotlinType(factoryImplementationClass);
}
private static @Nullable Constructor<?> findSingleConstructor(Constructor<?>[] constructors) { private static @Nullable Constructor<?> findSingleConstructor(Constructor<?>[] constructors) {
return (constructors.length == 1 ? constructors[0] : null); return (constructors.length == 1 ? constructors[0] : null);
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2024 the original author or authors. * Copyright 2002-2025 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -558,8 +558,7 @@ public class ReflectivePropertyAccessor implements PropertyAccessor {
private static boolean isKotlinProperty(Method method, String methodSuffix) { private static boolean isKotlinProperty(Method method, String methodSuffix) {
Class<?> clazz = method.getDeclaringClass(); Class<?> clazz = method.getDeclaringClass();
return KotlinDetector.isKotlinReflectPresent() && return KotlinDetector.isKotlinType(clazz) &&
KotlinDetector.isKotlinType(clazz) &&
KotlinDelegate.isKotlinProperty(method, methodSuffix); KotlinDelegate.isKotlinProperty(method, methodSuffix);
} }

View File

@ -868,8 +868,7 @@ public class Jackson2ObjectMapperBuilder {
// jackson-datatype-jsr310 not available // jackson-datatype-jsr310 not available
} }
// Kotlin present? if (KotlinDetector.isKotlinReflectPresent()) {
if (KotlinDetector.isKotlinPresent()) {
try { try {
Class<? extends Module> kotlinModuleClass = (Class<? extends Module>) Class<? extends Module> kotlinModuleClass = (Class<? extends Module>)
ClassUtils.forName("com.fasterxml.jackson.module.kotlin.KotlinModule", this.moduleClassLoader); ClassUtils.forName("com.fasterxml.jackson.module.kotlin.KotlinModule", this.moduleClassLoader);

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2024 the original author or authors. * Copyright 2002-2025 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -103,8 +103,7 @@ public abstract class AbstractNamedValueMethodArgumentResolver implements Handle
NamedValueInfo namedValueInfo = getNamedValueInfo(parameter); NamedValueInfo namedValueInfo = getNamedValueInfo(parameter);
MethodParameter nestedParameter = parameter.nestedIfOptional(); MethodParameter nestedParameter = parameter.nestedIfOptional();
boolean hasDefaultValue = KotlinDetector.isKotlinReflectPresent() && boolean hasDefaultValue = KotlinDetector.isKotlinType(parameter.getDeclaringClass()) &&
KotlinDetector.isKotlinType(parameter.getDeclaringClass()) &&
KotlinDelegate.hasDefaultValue(nestedParameter); KotlinDelegate.hasDefaultValue(nestedParameter);
Object resolvedName = resolveEmbeddedValuesAndExpressions(namedValueInfo.name); Object resolvedName = resolveEmbeddedValuesAndExpressions(namedValueInfo.name);
@ -276,7 +275,7 @@ public abstract class AbstractNamedValueMethodArgumentResolver implements Handle
WebDataBinder binder = binderFactory.createBinder(webRequest, null, namedValueInfo.name); WebDataBinder binder = binderFactory.createBinder(webRequest, null, namedValueInfo.name);
Class<?> parameterType = parameter.getParameterType(); Class<?> parameterType = parameter.getParameterType();
if (KotlinDetector.isKotlinPresent() && KotlinDetector.isInlineClass(parameterType)) { if (KotlinDetector.isInlineClass(parameterType)) {
Constructor<?> ctor = BeanUtils.findPrimaryConstructor(parameterType); Constructor<?> ctor = BeanUtils.findPrimaryConstructor(parameterType);
if (ctor != null) { if (ctor != null) {
parameterType = ctor.getParameterTypes()[0]; parameterType = ctor.getParameterTypes()[0];

View File

@ -242,13 +242,11 @@ public class InvocableHandlerMethod extends HandlerMethod {
protected @Nullable Object doInvoke(@Nullable Object... args) throws Exception { protected @Nullable Object doInvoke(@Nullable Object... args) throws Exception {
Method method = getBridgedMethod(); Method method = getBridgedMethod();
try { try {
if (KotlinDetector.isKotlinReflectPresent()) { if (KotlinDetector.isKotlinType(method.getDeclaringClass())) {
if (KotlinDetector.isSuspendingFunction(method)) { if (KotlinDetector.isSuspendingFunction(method)) {
return invokeSuspendingFunction(method, getBean(), args); return invokeSuspendingFunction(method, getBean(), args);
} }
else if (KotlinDetector.isKotlinType(method.getDeclaringClass())) { return KotlinDelegate.invokeFunction(method, getBean(), args);
return KotlinDelegate.invokeFunction(method, getBean(), args);
}
} }
return method.invoke(getBean(), args); return method.invoke(getBean(), args);
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2024 the original author or authors. * Copyright 2002-2025 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -191,12 +191,9 @@ public class InvocableHandlerMethod extends HandlerMethod {
Method method = getBridgedMethod(); Method method = getBridgedMethod();
boolean isSuspendingFunction = KotlinDetector.isSuspendingFunction(method); boolean isSuspendingFunction = KotlinDetector.isSuspendingFunction(method);
try { try {
if (KotlinDetector.isKotlinReflectPresent() && KotlinDetector.isKotlinType(method.getDeclaringClass())) { value = (KotlinDetector.isKotlinType(method.getDeclaringClass()) ?
value = KotlinDelegate.invokeFunction(method, getBean(), args, isSuspendingFunction, exchange); KotlinDelegate.invokeFunction(method, getBean(), args, isSuspendingFunction, exchange) :
} method.invoke(getBean(), args));
else {
value = method.invoke(getBean(), args);
}
} }
catch (IllegalArgumentException ex) { catch (IllegalArgumentException ex) {
assertTargetBean(getBridgedMethod(), getBean(), args); assertTargetBean(getBridgedMethod(), getBean(), args);

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2024 the original author or authors. * Copyright 2002-2025 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -195,7 +195,7 @@ public abstract class AbstractNamedValueArgumentResolver extends HandlerMethodAr
WebDataBinder binder = bindingContext.createDataBinder(exchange, namedValueInfo.name); WebDataBinder binder = bindingContext.createDataBinder(exchange, namedValueInfo.name);
Class<?> parameterType = parameter.getParameterType(); Class<?> parameterType = parameter.getParameterType();
if (KotlinDetector.isKotlinPresent() && KotlinDetector.isInlineClass(parameterType)) { if (KotlinDetector.isInlineClass(parameterType)) {
Constructor<?> ctor = BeanUtils.findPrimaryConstructor(parameterType); Constructor<?> ctor = BeanUtils.findPrimaryConstructor(parameterType);
if (ctor != null) { if (ctor != null) {
parameterType = ctor.getParameterTypes()[0]; parameterType = ctor.getParameterTypes()[0];
@ -222,8 +222,7 @@ public abstract class AbstractNamedValueArgumentResolver extends HandlerMethodAr
return Mono.fromSupplier(() -> { return Mono.fromSupplier(() -> {
Object value = null; Object value = null;
boolean hasDefaultValue = KotlinDetector.isKotlinReflectPresent() && boolean hasDefaultValue = KotlinDetector.isKotlinType(parameter.getDeclaringClass()) &&
KotlinDetector.isKotlinType(parameter.getDeclaringClass()) &&
KotlinDelegate.hasDefaultValue(parameter); KotlinDelegate.hasDefaultValue(parameter);
if (namedValueInfo.defaultValue != null) { if (namedValueInfo.defaultValue != null) {
value = resolveEmbeddedValuesAndExpressions(namedValueInfo.defaultValue); value = resolveEmbeddedValuesAndExpressions(namedValueInfo.defaultValue);