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

org.babyfish.jimmer.sql.fetcher.DtoMetadata Maven / Gradle / Ivy

There is a newer version: 0.9.19
Show newest version
package org.babyfish.jimmer.sql.fetcher;

import org.apache.commons.lang3.reflect.TypeUtils;
import org.babyfish.jimmer.Dto;
import org.babyfish.jimmer.impl.util.ClassCache;

import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
import java.util.Iterator;
import java.util.Map;
import java.util.Objects;
import java.util.function.Function;

public final class DtoMetadata {

    private static final ClassCache> cache =
            new ClassCache<>(DtoMetadata::create, false);

    private final Fetcher fetcher;

    private final Function converter;

    /**
     * This constructor should not be invoked by developer,
     * it is designed for code generator.
     * @param fetcher
     * @param converter
     */
    public DtoMetadata(Fetcher fetcher, Function converter) {
        this.fetcher = Objects.requireNonNull(fetcher, "fetch cannot be null");
        this.converter = Objects.requireNonNull(converter, "converter cannot be null");
    }

    public Fetcher getFetcher() {
        return fetcher;
    }

    public Function getConverter() {
        return converter;
    }

    @Override
    public int hashCode() {
        return Objects.hash(fetcher, converter);
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        DtoMetadata that = (DtoMetadata) o;
        return fetcher.equals(that.fetcher) && converter.equals(that.converter);
    }

    @Override
    public String toString() {
        return "ViewMetadata{" +
                "fetcher=" + fetcher +
                ", converter=" + converter +
                '}';
    }

    @SuppressWarnings("unchecked")
    public static > DtoMetadata of(Class dtoType) {
        return (DtoMetadata) cache.get(dtoType);
    }

    private static DtoMetadata create(Class dtoType) {
        if (!Dto.class.isAssignableFrom(dtoType)) {
            throw new IllegalArgumentException(
                    "The type \"" +
                            dtoType.getName() +
                            "\" does not inherit \"" +
                            Dto.class.getName() +
                            "\""
            );
        }
        Iterator itr = TypeUtils.getTypeArguments(dtoType, Dto.class).values().iterator();
        if (!itr.hasNext()) {
            throw new IllegalArgumentException(
                    "The type \"" +
                            dtoType.getName() +
                            "\" does not specify the generic parameter of \"" +
                            Dto.class.getName() +
                            "\""
            );
        }
        Type type = itr.next();
        if (!(type instanceof Class) || !((Class)type).isInterface()) {
            throw new IllegalArgumentException(
                    "The type \"" +
                            dtoType.getName() +
                            "\" is illegal, the generic parameter of \"" +
                            Dto.class.getName() +
                            "\" must be specified"
            );
        }
        Class entityType = (Class)type;
        Field metadataField;
        try {
            metadataField = dtoType.getDeclaredField("METADATA");
            if (!Modifier.isStatic(metadataField.getModifiers()) ||
                    !Modifier.isFinal(metadataField.getModifiers())) {
                metadataField = null;
            }
        } catch (NoSuchFieldException ex) {
            metadataField = null;
        }
        if (metadataField == null) {
            throw new IllegalArgumentException(
                    "The type \"" +
                            dtoType.getName() +
                            "\" is illegal, there is not static final field \"METADATA\""
            );
        }
        if (metadataField.getType() != DtoMetadata.class) {
            throw new IllegalArgumentException(
                    "The type \"" +
                            dtoType.getName() +
                            "\" is illegal, the type of \"" +
                            metadataField +
                            "\" must be \"" +
                            DtoMetadata.class.getName() +
                            "\""
            );
        }
        TypeVariable[] typeParameters = DtoMetadata.class.getTypeParameters();
        Map, Type> typeArgumentMap =
                TypeUtils.getTypeArguments(metadataField.getGenericType(), DtoMetadata.class);
        if (typeArgumentMap.get(typeParameters[0]) != entityType) {
            throw new IllegalArgumentException(
                    "The type \"" +
                            dtoType.getName() +
                            "\" is illegal, the first generic argument of the return type of \"" +
                            metadataField +
                            "\" must be \"" +
                            entityType.getName() +
                            "\""
            );
        }
        if (typeArgumentMap.get(typeParameters[1]) != dtoType) {
            throw new IllegalArgumentException(
                    "The type \"" +
                            dtoType.getName() +
                            "\" is illegal, the first generic argument of the return type of \"" +
                            metadataField +
                            "\" must be \"" +
                            dtoType.getName() +
                            "\""
            );
        }
        metadataField.setAccessible(true);
        try {
            return (DtoMetadata)metadataField.get(null);
        } catch (IllegalAccessException ex) {
            throw new AssertionError("Internal bug", ex);
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy