/*
* Copyright 2017-2020 original authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.micronaut.core.beans;
import io.micronaut.core.annotation.AnnotationMetadataProvider;
import io.micronaut.core.beans.exceptions.IntrospectionException;
import io.micronaut.core.convert.ArgumentConversionContext;
import io.micronaut.core.convert.ConversionContext;
import io.micronaut.core.convert.ConversionError;
import io.micronaut.core.convert.exceptions.ConversionErrorException;
import io.micronaut.core.type.Argument;
import io.micronaut.core.util.ArgumentUtils;
import edu.umd.cs.findbugs.annotations.NonNull;
import edu.umd.cs.findbugs.annotations.Nullable;
import java.util.Collection;
import java.util.Optional;
Wraps a bean allowing to read and write its properties via a underlying BeanIntrospection
. Author: graemerocher Type parameters: - <T> – The bean type.
Since: 1.1
/**
* Wraps a bean allowing to read and write its properties via a underlying {@link BeanIntrospection}.
*
* @param <T> The bean type.
* @author graemerocher
* @since 1.1
*/
public interface BeanWrapper<T> extends AnnotationMetadataProvider {
Returns: The introspection.
/**
* @return The introspection.
*/
@NonNull BeanIntrospection<T> getIntrospection();
Returns: The bean;
/**
* @return The bean;
*/
@NonNull T getBean();
The property names.
Returns: The property names
/**
* The property names.
*
* @return The property names
*/
default @NonNull String[] getPropertyNames() {
return getIntrospection().getPropertyNames();
}
The properties.
Returns: The properties
/**
* The properties.
* @return The properties
*/
default @NonNull Collection<BeanProperty<T, Object>> getBeanProperties() {
return getIntrospection().getBeanProperties();
}
Get the property value of the given type or throw an exception if it is unobtainable.
Params: - name – The name
- type – The type
Type parameters: - <P> – The property generic type
Throws: - IntrospectionException – if no property exists
- ConversionErrorException – if the property cannot be converted to the given type
Returns: The property value
/**
* Get the property value of the given type or throw an exception if it is unobtainable.
*
* @param name The name
* @param type The type
* @param <P> The property generic type
* @return The property value
* @throws IntrospectionException if no property exists
* @throws ConversionErrorException if the property cannot be converted to the given type
*/
default @NonNull <P> P getRequiredProperty(@NonNull String name, @NonNull Class<P> type) {
ArgumentUtils.requireNonNull("name", name);
ArgumentUtils.requireNonNull("type", type);
final Argument<P> argument = Argument.of(type);
return getRequiredProperty(name, argument);
}
Get the property value of the given type or throw an exception if it is unobtainable.
Params: - name – The name
- argument – The argument type
Type parameters: - <P> – The property generic type
Throws: - IntrospectionException – if no property exists
- ConversionErrorException – if the property cannot be converted to the given type
Returns: The property value
/**
* Get the property value of the given type or throw an exception if it is unobtainable.
*
* @param name The name
* @param argument The argument type
* @param <P> The property generic type
* @return The property value
* @throws IntrospectionException if no property exists
* @throws ConversionErrorException if the property cannot be converted to the given type
*/
default <P> P getRequiredProperty(@NonNull String name, @NonNull Argument<P> argument) {
ArgumentUtils.requireNonNull("name", name);
ArgumentUtils.requireNonNull("argument", argument);
final ArgumentConversionContext<P> context = ConversionContext.of(argument);
return getRequiredProperty(name, context);
}
Get the property value of the given type or throw an exception if it is unobtainable.
Params: - name – The name
- context – The type
Type parameters: - <P> – The property generic type
Throws: - IntrospectionException – if no property exists
- ConversionErrorException – if the property cannot be converted to the given type
Returns: The property value
/**
* Get the property value of the given type or throw an exception if it is unobtainable.
* @param name The name
* @param context The type
* @param <P> The property generic type
* @return The property value
* @throws IntrospectionException if no property exists
* @throws ConversionErrorException if the property cannot be converted to the given type
*/
default @NonNull <P> P getRequiredProperty(@NonNull String name, @NonNull ArgumentConversionContext<P> context) {
ArgumentUtils.requireNonNull("name", name);
ArgumentUtils.requireNonNull("type", context);
return getIntrospection().getProperty(name)
.map(prop -> {
final Optional<P> converted = prop.get(getBean(), context);
return converted.orElseThrow(() -> {
final ConversionError conversionError = context.getLastError().orElseGet(() -> new ConversionError() {
@Override
public Exception getCause() {
return new IntrospectionException("Property of type [" + prop.getType() + "] cannot be converted to type: " + context.getArgument().getType());
}
@Override
public Optional<Object> getOriginalValue() {
return Optional.ofNullable(prop.get(getBean()));
}
});
return new ConversionErrorException(context.getArgument(), conversionError);
});
})
.orElseThrow(() -> new IntrospectionException("No property found for name: " + name));
}
Get the property of the given name and type.
Params: - name – The name
- type – The required type
Type parameters: - <P> – The required generic type
Returns: The property if found and can be converted to the given type
/**
* Get the property of the given name and type.
* @param name The name
* @param type The required type
* @param <P> The required generic type
* @return The property if found and can be converted to the given type
*/
default @NonNull <P> Optional<P> getProperty(@NonNull String name, @NonNull Class<P> type) {
ArgumentUtils.requireNonNull("name", name);
ArgumentUtils.requireNonNull("type", type);
final Argument<P> argument = Argument.of(type);
return getProperty(name, argument);
}
Get the property of the given name and type.
Params: - name – The name
- type – The required type
Type parameters: - <P> – The required generic type
Returns: The property if found and can be converted to the given type
/**
* Get the property of the given name and type.
* @param name The name
* @param type The required type
* @param <P> The required generic type
* @return The property if found and can be converted to the given type
*/
default <P> Optional<P> getProperty(@NonNull String name, Argument<P> type) {
ArgumentUtils.requireNonNull("name", name);
ArgumentUtils.requireNonNull("type", type);
final ArgumentConversionContext<P> context = ConversionContext.of(type);
return getProperty(name, context);
}
Get the property of the given name and type.
Params: - name – The name
- context – The conversion context
Type parameters: - <P> – The required generic type
Returns: The property if found and can be converted to the given type
/**
* Get the property of the given name and type.
* @param name The name
* @param context The conversion context
* @param <P> The required generic type
* @return The property if found and can be converted to the given type
*/
default <P> Optional<P> getProperty(@NonNull String name, ArgumentConversionContext<P> context) {
ArgumentUtils.requireNonNull("name", name);
ArgumentUtils.requireNonNull("context", context);
return getIntrospection().getProperty(name)
.flatMap(prop -> prop.get(getBean(), context));
}
Sets a property of the given name to the given value.
Params: - name – The name
- value – The value
Throws: - ConversionErrorException – if the value cannot be converted to the underlying property type.
Returns: This wrapper
/**
* Sets a property of the given name to the given value.
* @param name The name
* @param value The value
* @return This wrapper
* @throws ConversionErrorException if the value cannot be converted to the underlying property type.
*/
default BeanWrapper<T> setProperty(@NonNull String name, @Nullable Object value) {
ArgumentUtils.requireNonNull("name", name);
getIntrospection()
.getProperty(name)
.ifPresent(prop -> prop.convertAndSet(getBean(), value));
return this;
}
Obtain a bean wrapper for the given bean.
Params: - bean – The bean
Type parameters: - <T2> – The bean type
Throws: - IntrospectionException – If the wrapper cannot be created
Returns: The wrapper
/**
* Obtain a bean wrapper for the given bean.
* @param bean The bean
* @param <T2> The bean type
* @return The wrapper
* @throws io.micronaut.core.beans.exceptions.IntrospectionException If the wrapper cannot be created
*/
static @NonNull <T2> BeanWrapper<T2> getWrapper(@NonNull T2 bean) {
ArgumentUtils.requireNonNull("bean", bean);
@SuppressWarnings("unchecked") final Class<T2> aClass = (Class<T2>) bean.getClass();
final BeanIntrospection<T2> introspection = BeanIntrospection.getIntrospection(aClass);
return new DefaultBeanWrapper<>(bean, introspection);
}
Obtain a bean wrapper for the given bean.
Params: - bean – The bean
Type parameters: - <T2> – The bean type
Throws: - IntrospectionException – If the wrapper cannot be created
Returns: The wrapper
/**
* Obtain a bean wrapper for the given bean.
* @param bean The bean
* @param <T2> The bean type
* @return The wrapper
* @throws io.micronaut.core.beans.exceptions.IntrospectionException If the wrapper cannot be created
*/
@SuppressWarnings("unchecked")
static @NonNull <T2> Optional<BeanWrapper<T2>> findWrapper(@NonNull T2 bean) {
ArgumentUtils.requireNonNull("bean", bean);
@SuppressWarnings("unchecked") final Class<T2> aClass = (Class<T2>) bean.getClass();
return BeanIntrospector.SHARED.findIntrospection(aClass).map(i ->
new DefaultBeanWrapper(bean, i)
);
}
Obtain a bean wrapper for the given bean.
Params: - type – the type
- bean – The bean
Type parameters: - <T2> – The bean type
Throws: - IntrospectionException – If the wrapper cannot be created
Returns: The wrapper
/**
* Obtain a bean wrapper for the given bean.
* @param type the type
* @param bean The bean
* @param <T2> The bean type
* @return The wrapper
* @throws io.micronaut.core.beans.exceptions.IntrospectionException If the wrapper cannot be created
*/
@SuppressWarnings("unchecked")
static @NonNull <T2> Optional<BeanWrapper<T2>> findWrapper(Class<T2> type, @NonNull T2 bean) {
ArgumentUtils.requireNonNull("type", type);
ArgumentUtils.requireNonNull("bean", bean);
return BeanIntrospector.SHARED.findIntrospection(type).map(i ->
new DefaultBeanWrapper(bean, i)
);
}
Obtain a bean wrapper for the given bean.
Params: - type – the type
- bean – The bean
Type parameters: - <T2> – The bean type
Throws: - IntrospectionException – If the wrapper cannot be created
Returns: The wrapper
/**
* Obtain a bean wrapper for the given bean.
* @param type the type
* @param bean The bean
* @param <T2> The bean type
* @return The wrapper
* @throws io.micronaut.core.beans.exceptions.IntrospectionException If the wrapper cannot be created
*/
static @NonNull <T2> BeanWrapper<T2> getWrapper(Class<T2> type, @NonNull T2 bean) {
ArgumentUtils.requireNonNull("type", type);
ArgumentUtils.requireNonNull("bean", bean);
final BeanIntrospection<T2> introspection = BeanIntrospection.getIntrospection(type);
return new DefaultBeanWrapper<>(bean, introspection);
}
}