/*
 * 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:
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:
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:
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:
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:
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:
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:
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:
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); } }