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

org.apache.bval.jsr.metadata.Meta Maven / Gradle / Ivy

/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you 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
 *
 * http://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 org.apache.bval.jsr.metadata;

import java.lang.annotation.ElementType;
import java.lang.reflect.AnnotatedElement;
import java.lang.reflect.AnnotatedType;
import java.lang.reflect.Constructor;
import java.lang.reflect.Executable;
import java.lang.reflect.Field;
import java.lang.reflect.Member;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
import java.util.Map;
import java.util.Objects;

import org.apache.bval.util.EmulatedAnnotatedType;
import org.apache.bval.util.Lazy;
import org.apache.bval.util.Validate;
import org.apache.bval.util.reflection.TypeUtils;

/**
 * Validation class model.
 *
 * @param 
 */
public abstract class Meta {

    public static class ForClass extends Meta> {
        private final AnnotatedType annotatedType;

        public ForClass(Class host) {
            super(host, ElementType.TYPE);
            this.annotatedType = EmulatedAnnotatedType.wrap(host);
        }

        @Override
        public final Class getDeclaringClass() {
            return getHost();
        }

        @Override
        public Type getType() {
            return getHost();
        }

        @Override
        public AnnotatedType getAnnotatedType() {
            return annotatedType;
        }

        @Override
        public String getName() {
            return getHost().getName();
        }

        @Override
        public Meta getParent() {
            return null;
        }
    }

    public static abstract class ForMember extends Meta {
        @SuppressWarnings({ "rawtypes", "unchecked" })
        private final Lazy>> parent = new Lazy<>(() -> new Meta.ForClass(getDeclaringClass()));

        protected ForMember(M host, ElementType elementType) {
            super(host, elementType);
        }

        @Override
        public Class getDeclaringClass() {
            return getHost().getDeclaringClass();
        }

        @Override
        public Meta> getParent() {
            return parent.get();
        }
    }

    public static class ForField extends ForMember {

        public ForField(Field host) {
            super(host, ElementType.FIELD);
        }

        @Override
        public Type getType() {
            return getHost().getGenericType();
        }

        @Override
        public AnnotatedType getAnnotatedType() {
            return getHost().getAnnotatedType();
        }

        @Override
        public String getName() {
            return getHost().getName();
        }
    }

    public static abstract class ForExecutable extends ForMember {

        protected ForExecutable(E host, ElementType elementType) {
            super(host, elementType);
        }

        @Override
        public AnnotatedType getAnnotatedType() {
            return getHost().getAnnotatedReturnType();
        }
    }

    public static class ForConstructor extends ForExecutable> {

        public ForConstructor(Constructor host) {
            super(host, ElementType.CONSTRUCTOR);
        }

        @Override
        public Type getType() {
            return getHost().getDeclaringClass();
        }

        @Override
        public String getName() {
            return getHost().getDeclaringClass().getSimpleName();
        }
    }

    public static class ForMethod extends ForExecutable {

        public ForMethod(Method host) {
            super(host, ElementType.METHOD);
        }

        @Override
        public Type getType() {
            return getHost().getGenericReturnType();
        }

        @Override
        public String getName() {
            return getHost().getName();
        }
    }

    public static class ForCrossParameter extends Meta {

        private final Meta parent;

        public ForCrossParameter(Meta parent) {
            super(parent.getHost(), parent.getElementType());
            this.parent = parent;
        }

        @Override
        public Type getType() {
            return Object[].class;
        }

        @Override
        public String getName() {
            return "";
        }

        @Override
        public String describeHost() {
            return String.format("%s of %s", getName(), getHost());
        }

        @Override
        public Meta getParent() {
            return parent;
        }

        @Override
        public Class getDeclaringClass() {
            return getHost().getDeclaringClass();
        }

        @Override
        public AnnotatedType getAnnotatedType() {
            return getHost().getAnnotatedReturnType();
        }
    }

    public static class ForParameter extends Meta {

        private final String name;
        private final Lazy> parent = new Lazy<>(this::computeParent);

        public ForParameter(Parameter host, String name) {
            super(host, ElementType.PARAMETER);
            this.name = Validate.notNull(name, "name");
        }

        @Override
        public Type getType() {
            return getHost().getParameterizedType();
        }

        @Override
        public Class getDeclaringClass() {
            return getHost().getDeclaringExecutable().getDeclaringClass();
        }

        @Override
        public AnnotatedType getAnnotatedType() {
            return getHost().getAnnotatedType();
        }

        @Override
        public String getName() {
            return name;
        }

        @Override
        public String describeHost() {
            return String.format("%s of %s", getName(), getHost().getDeclaringExecutable());
        }

        @Override
        public Meta getParent() {
            return parent.get();
        }

        private Meta computeParent() {
            final Executable exe = getHost().getDeclaringExecutable();
            return exe instanceof Method ? new Meta.ForMethod((Method) exe)
                : new Meta.ForConstructor<>((Constructor) exe);
        }
    }

    public static class ForContainerElement extends Meta {

        private final Meta parent;
        private final ContainerElementKey key;

        public ForContainerElement(Meta parent, ContainerElementKey key) {
            super(key.getAnnotatedType(), ElementType.TYPE_USE);
            this.parent = Validate.notNull(parent, "parent");
            this.key = Validate.notNull(key, "key");
        }

        @Override
        public Type getType() {
            Type result = getHost().getType();
            if (result instanceof TypeVariable) {
                final Type parentType = parent.getType();
                if (parentType instanceof ParameterizedType) {
                    final Map, Type> typeArguments =
                        TypeUtils.getTypeArguments((ParameterizedType) parentType);
                    if (typeArguments.containsKey(result)) {
                        return typeArguments.get(result);
                    }
                }
            }
            return result;
        }

        @Override
        public Class getDeclaringClass() {
            return parent.getDeclaringClass();
        }

        @Override
        public AnnotatedType getAnnotatedType() {
            return key.getAnnotatedType();
        }

        public Integer getTypeArgumentIndex() {
            return key.getTypeArgumentIndex();
        }

        @Override
        public String getName() {
            return key.toString();
        }

        @Override
        public String describeHost() {
            return String.format("%s of %s", key, parent);
        }

        @Override
        public Meta getParent() {
            return parent;
        }
    }

    private final E host;
    private final ElementType elementType;

    protected Meta(E host, ElementType elementType) {
        super();
        this.host = Validate.notNull(host, "host");
        this.elementType = Validate.notNull(elementType, "elementType");
    }

    public E getHost() {
        return host;
    }

    public ElementType getElementType() {
        return elementType;
    }

    public abstract Type getType();

    public abstract Class getDeclaringClass();

    public abstract AnnotatedType getAnnotatedType();

    public abstract String getName();

    public abstract Meta getParent();

    @Override
    public final String toString() {
        return String.format("%s.%s(%s)", Meta.class.getSimpleName(), getClass().getSimpleName(), describeHost());
    }

    public String describeHost() {
        return host.toString();
    }

    @Override
    public boolean equals(Object obj) {
        if (obj == this) {
            return true;
        }
        if (!obj.getClass().equals(getClass())) {
            return false;
        }
        return Objects.equals(((Meta) obj).getHost(), getHost());
    }

    @Override
    public int hashCode() {
        return Objects.hash(getHost());
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy