AssignableConvertHandler.java
package space.sunqian.common.object.convert.handlers;
import space.sunqian.annotations.Nonnull;
import space.sunqian.annotations.Nullable;
import space.sunqian.common.base.option.Option;
import space.sunqian.common.object.convert.ConvertOption;
import space.sunqian.common.object.convert.ObjectConverter;
import space.sunqian.common.reflect.TypeKit;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
import java.lang.reflect.WildcardType;
import java.util.Objects;
/**
* The default first {@link ObjectConverter.Handler} of {@link ObjectConverter#defaultConverter()}, mainly used to
* determine whether it is possible to return the source object directly without creating a new object. Its conversion
* logic is:
* <ol>
* <li>
* If the specified source type equals to the target type, returns the source object itself;
* </li>
* <li>
* If the {@link ConvertOption#STRICT_TYPE_MODE} option is enabled, returns
* {@link ObjectConverter.Status#HANDLER_CONTINUE} for target type of {@link WildcardType};
* Otherwise, recursively convert their bounds type using the {@code converter} parameter;
* </li>
* <li>
* If the target type is assignable from the specified source type, returns the source object itself;
* </li>
* <li>
* Otherwise, returns {@link ObjectConverter.Status#HANDLER_CONTINUE}.
* </li>
* </ol>
*
* @author sunqian
*/
public class AssignableConvertHandler implements ObjectConverter.Handler {
@Override
public Object convert(
@Nullable Object src,
@Nonnull Type srcType,
@Nonnull Type target,
@Nonnull ObjectConverter converter,
@Nonnull Option<?, ?> @Nonnull ... options
) throws Exception {
if (Objects.equals(target, srcType)) {
return src;
}
if (Option.containsKey(ConvertOption.STRICT_TYPE_MODE, options)) {
// strict mode, wildcard is unsupported
if (target instanceof WildcardType) {
return ObjectConverter.Status.HANDLER_CONTINUE;
}
} else {
// non-strict mode, wildcard and type variable will be considered as their bounds type
if (target instanceof WildcardType) {
WildcardType wildcard = (WildcardType) target;
Type superType = TypeKit.getLowerBound(wildcard);
if (superType != null) {
return converter.convert(src, srcType, superType, options);
}
return converter.convert(src, srcType, TypeKit.getUpperBound(wildcard), options);
}
if (target instanceof TypeVariable<?>) {
return converter.convert(src, srcType, ((TypeVariable<?>) target).getBounds()[0], options);
}
}
if (TypeKit.isAssignable(target, srcType)) {
return src;
}
return ObjectConverter.Status.HANDLER_CONTINUE;
}
}