
infra.beans.factory.aot.BeanDefinitionPropertyValueCodeGeneratorDelegates Maven / Gradle / Ivy
The newest version!
/*
* Copyright 2017 - 2024 the original author or authors.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see [https://www.gnu.org/licenses/]
*/
package infra.beans.factory.aot;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import infra.aot.generate.GeneratedMethod;
import infra.aot.generate.GeneratedMethods;
import infra.aot.generate.ValueCodeGenerator;
import infra.aot.generate.ValueCodeGenerator.Delegate;
import infra.aot.generate.ValueCodeGeneratorDelegates;
import infra.aot.generate.ValueCodeGeneratorDelegates.CollectionDelegate;
import infra.aot.generate.ValueCodeGeneratorDelegates.MapDelegate;
import infra.beans.factory.config.BeanReference;
import infra.beans.factory.config.RuntimeBeanReference;
import infra.beans.factory.config.TypedStringValue;
import infra.beans.factory.support.ManagedList;
import infra.beans.factory.support.ManagedMap;
import infra.beans.factory.support.ManagedSet;
import infra.javapoet.AnnotationSpec;
import infra.javapoet.CodeBlock;
/**
* Code generator {@link Delegate} for common bean definition property values.
*
* @author Stephane Nicoll
* @author Harry Yang
* @since 4.0
*/
abstract class BeanDefinitionPropertyValueCodeGeneratorDelegates {
/**
* Return the {@link Delegate} implementations for common bean definition
* property value types. These are:
*
* - {@link ManagedList},
* - {@link ManagedSet},
* - {@link ManagedMap},
* - {@link LinkedHashMap},
* - {@link BeanReference},
* - {@link TypedStringValue}.
*
* When combined with {@linkplain ValueCodeGeneratorDelegates#INSTANCES the
* delegates for common value types}, this should be added first as they have
* special handling for list, set, and map.
*/
public static final List INSTANCES = List.of(
new ManagedListDelegate(),
new ManagedSetDelegate(),
new ManagedMapDelegate(),
new LinkedHashMapDelegate(),
new BeanReferenceDelegate(),
new TypedStringValueDelegate()
);
/**
* {@link Delegate} for {@link ManagedList} types.
*/
private static class ManagedListDelegate extends CollectionDelegate> {
public ManagedListDelegate() {
super(ManagedList.class, CodeBlock.of("new $T()", ManagedList.class));
}
}
/**
* {@link Delegate} for {@link ManagedSet} types.
*/
private static class ManagedSetDelegate extends CollectionDelegate> {
public ManagedSetDelegate() {
super(ManagedSet.class, CodeBlock.of("new $T()", ManagedSet.class));
}
}
/**
* {@link Delegate} for {@link ManagedMap} types.
*/
private static class ManagedMapDelegate implements Delegate {
private static final CodeBlock EMPTY_RESULT = CodeBlock.of("$T.ofEntries()", ManagedMap.class);
@Override
public CodeBlock generateCode(ValueCodeGenerator valueCodeGenerator, Object value) {
if (value instanceof ManagedMap, ?> managedMap) {
return generateManagedMapCode(valueCodeGenerator, managedMap);
}
return null;
}
private CodeBlock generateManagedMapCode(ValueCodeGenerator valueCodeGenerator,
ManagedMap managedMap) {
if (managedMap.isEmpty()) {
return EMPTY_RESULT;
}
CodeBlock.Builder code = CodeBlock.builder();
code.add("$T.ofEntries(", ManagedMap.class);
Iterator> iterator = managedMap.entrySet().iterator();
while (iterator.hasNext()) {
Entry, ?> entry = iterator.next();
code.add("$T.entry($L,$L)", Map.class,
valueCodeGenerator.generateCode(entry.getKey()),
valueCodeGenerator.generateCode(entry.getValue()));
if (iterator.hasNext()) {
code.add(", ");
}
}
code.add(")");
return code.build();
}
}
/**
* {@link Delegate} for {@link Map} types.
*/
private static class LinkedHashMapDelegate extends MapDelegate {
@Override
protected CodeBlock generateMapCode(ValueCodeGenerator valueCodeGenerator, Map, ?> map) {
GeneratedMethods generatedMethods = valueCodeGenerator.getGeneratedMethods();
if (map instanceof LinkedHashMap, ?> && generatedMethods != null) {
return generateLinkedHashMapCode(valueCodeGenerator, generatedMethods, map);
}
return super.generateMapCode(valueCodeGenerator, map);
}
private CodeBlock generateLinkedHashMapCode(ValueCodeGenerator valueCodeGenerator,
GeneratedMethods generatedMethods, Map, ?> map) {
GeneratedMethod generatedMethod = generatedMethods.add("getMap", method -> {
method.addAnnotation(AnnotationSpec
.builder(SuppressWarnings.class)
.addMember("value", "{\"rawtypes\", \"unchecked\"}")
.build());
method.returns(Map.class);
method.addStatement("$T map = new $T($L)", Map.class,
LinkedHashMap.class, map.size());
map.forEach((key, value) -> method.addStatement("map.put($L, $L)",
valueCodeGenerator.generateCode(key),
valueCodeGenerator.generateCode(value)));
method.addStatement("return map");
});
return CodeBlock.of("$L()", generatedMethod.getName());
}
}
/**
* {@link Delegate} for {@link BeanReference} types.
*/
private static class BeanReferenceDelegate implements Delegate {
@Override
public CodeBlock generateCode(ValueCodeGenerator valueCodeGenerator, Object value) {
if (value instanceof RuntimeBeanReference runtimeBeanReference
&& runtimeBeanReference.getBeanType() != null) {
return CodeBlock.of("new $T($T.class)", RuntimeBeanReference.class,
runtimeBeanReference.getBeanType());
}
else if (value instanceof BeanReference beanReference) {
return CodeBlock.of("new $T($S)", RuntimeBeanReference.class,
beanReference.getBeanName());
}
return null;
}
}
/**
* {@link Delegate} for {@link TypedStringValue} types.
*/
private static class TypedStringValueDelegate implements Delegate {
@Override
public CodeBlock generateCode(ValueCodeGenerator valueCodeGenerator, Object value) {
if (value instanceof TypedStringValue typedStringValue) {
return generateTypeStringValueCode(valueCodeGenerator, typedStringValue);
}
return null;
}
private CodeBlock generateTypeStringValueCode(ValueCodeGenerator valueCodeGenerator, TypedStringValue typedStringValue) {
String value = typedStringValue.getValue();
if (typedStringValue.hasTargetType()) {
return CodeBlock.of("new $T($S, $L)", TypedStringValue.class, value,
valueCodeGenerator.generateCode(typedStringValue.getTargetType()));
}
return valueCodeGenerator.generateCode(value);
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy