All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.github.leeonky.util.BeanClass Maven / Gradle / Ivy

The newest version!
package com.github.leeonky.util;

import java.lang.annotation.Annotation;
import java.lang.reflect.Array;
import java.lang.reflect.Type;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

import static java.util.Arrays.asList;
import static java.util.Optional.ofNullable;
import static java.util.stream.Collectors.toList;

public class BeanClass {
    private final static Map, BeanClass> instanceCache = new ConcurrentHashMap<>();
    private static Converter converter = Converter.getInstance();
    private final TypeInfo typeInfo;
    private final Class type;

    protected BeanClass(Class type) {
        this.type = Objects.requireNonNull(type);
        typeInfo = TypeInfo.create(this);
    }

    @SuppressWarnings("unchecked")
    public static  BeanClass create(Class type) {
        return (BeanClass) instanceCache.computeIfAbsent(type, BeanClass::new);
    }

    public static  Optional cast(Object value, Class type) {
        return ofNullable(value)
                .filter(type::isInstance)
                .map(type::cast);
    }

    public static BeanClass create(GenericType type) {
        if (!type.hasTypeArguments())
            return create(type.getRawType());
        return GenericBeanClass.create(type);
    }

    @SuppressWarnings("unchecked")
    public static  Class getClass(T instance) {
        return (Class) Objects.requireNonNull(instance).getClass();
    }

    public static  BeanClass createFrom(T instance) {
        return create(getClass(instance));
    }

    public static Converter getConverter() {
        return converter;
    }

    public static void setConverter(Converter converter) {
        BeanClass.converter = converter;
    }

    public Class getType() {
        return type;
    }

    public String getName() {
        return type.getName();
    }

    public String getSimpleName() {
        return type.getSimpleName();
    }

    public Map> getPropertyReaders() {
        return typeInfo.getReaders();
    }

    public Map> getPropertyWriters() {
        return typeInfo.getWriters();
    }

    public Object getPropertyValue(T bean, String property) {
        return getPropertyReader(property).getValue(bean);
    }

    public PropertyReader getPropertyReader(String property) {
        return typeInfo.getReader(property);
    }

    public BeanClass setPropertyValue(T bean, String property, Object value) {
        getPropertyWriter(property).setValue(bean, value);
        return this;
    }

    public PropertyWriter getPropertyWriter(String property) {
        return typeInfo.getWriter(property);
    }

    public T newInstance(Object... args) {
        return Classes.newInstance(type, args);
    }

    public Object createCollection(Collection elements) {
        return CollectionHelper.createCollection(elements, this);
    }

    public Object getPropertyChainValue(T object, String chain) {
        return getPropertyChainValue(object, Property.toChainNodes(chain));
    }

    public Object getPropertyChainValue(T object, List chain) {
        return getPropertyChainValueInner(chain, 0, object, new LinkedList<>(chain));
    }

    @SuppressWarnings("unchecked")
    private Object getPropertyChainValueInner(List originalChain, int level, T object, LinkedList chain) {
        if (chain.isEmpty())
            return object;
        if (object == null)
            throw new NullPointerInChainException(originalChain, level);
        Object p = chain.removeFirst();
        PropertyReader propertyReader = getPropertyReader(p.toString());
        return propertyReader.getType().getPropertyChainValueInner(originalChain, level + 1,
                propertyReader.getValue(object), chain);
    }

    public PropertyReader getPropertyChainReader(String chain) {
        return getPropertyChainReader(Property.toChainNodes(chain));
    }

    public PropertyReader getPropertyChainReader(List chain) {
        return getPropertyChainReaderInner(new LinkedList<>(chain));
    }

    private PropertyReader getPropertyChainReaderInner(LinkedList chain) {
        return getPropertyReader((String) chain.removeFirst()).getPropertyChainReader(chain);
    }

    @SuppressWarnings("unchecked")
    public T createDefault() {
        return (T) Array.get(Array.newInstance(getType(), 1), 0);
    }

    public boolean hasTypeArguments() {
        return false;
    }

    public Optional> getTypeArguments(int position) {
        return Optional.empty();
    }

    public BeanClass getElementType() {
        if (type.isArray())
            return BeanClass.create(type.getComponentType());
        if (Iterable.class.isAssignableFrom(type))
            return getTypeArguments(0).orElseGet(() -> BeanClass.create(Object.class));
        return null;
    }

    public BeanClass getElementOrPropertyType() {
        BeanClass elementType = getElementType();
        return elementType == null ? this : elementType;
    }

    @Override
    public int hashCode() {
        return Objects.hash(BeanClass.class, type);
    }

    @Override
    public boolean equals(Object obj) {
        return obj.getClass().equals(BeanClass.class) && Objects.equals(((BeanClass) obj).getType(), type);
    }

    @SuppressWarnings("unchecked")
    public  BeanClass getSuper(Class target) {
        List superBeanClasses = supers();
        return (BeanClass) superBeanClasses.stream().filter(beanClass -> beanClass.getType().equals(target))
                .findFirst().orElseGet(() -> (BeanClass) superBeanClasses.stream()
                        .map(beanClass -> beanClass.getSuper(target))
                        .filter(Objects::nonNull).findFirst().orElse(null));
    }

    private List supers() {
        List suppers = new ArrayList<>(asList(type.getGenericInterfaces()));
        suppers.add(type.getGenericSuperclass());
        return suppers.stream().filter(Objects::nonNull)
                .map(t -> BeanClass.create(GenericType.createGenericType(t)))
                .collect(toList());
    }

    public boolean isCollection() {
        return getType().isArray() || Iterable.class.isAssignableFrom(getType());
    }

    public Map> getProperties() {
        return typeInfo.getProperties();
    }

    public Property getProperty(String name) {
        return typeInfo.getProperty(name);
    }

    public boolean isInstance(Object instance) {
        return type.isInstance(instance);
    }

    public boolean isInheritedFrom(Class type) {
        return type.isAssignableFrom(this.type);
    }

    public  Optional annotation(Class annotationClass) {
        return ofNullable(getAnnotation(annotationClass));
    }

    public  A getAnnotation(Class annotationClass) {
        return type.getAnnotation(annotationClass);
    }
}