/*
 * 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.descriptor;

import java.lang.annotation.ElementType;
import java.lang.reflect.AnnotatedElement;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.validation.metadata.ConstraintDescriptor;
import javax.validation.metadata.ElementDescriptor;

import org.apache.bval.jsr.metadata.Meta;
import org.apache.bval.util.Validate;
import org.apache.bval.util.reflection.TypeUtils;

public abstract class ElementD<E extends AnnotatedElement, R extends MetadataReader.ForElement<E, ?>>
    implements ElementDescriptor {

    public static abstract class NonRoot<P extends ElementD<?, ?>, E extends AnnotatedElement, R extends MetadataReader.ForElement<E, ?>>
        extends ElementD<E, R> {

        protected final P parent;

        protected NonRoot(R reader, P parent) {
            super(reader);
            this.parent = Validate.notNull(parent, "parent");
        }

        public P getParent() {
            return parent;
        }

        @Override
        public final Type getGenericType() {
            if (TypeUtils.containsTypeVariables(genericType)) {
                final Map<TypeVariable<?>, Type> args =
                    TypeUtils.getTypeArguments(parent.getGenericType(), Object.class);
                return TypeUtils.unrollVariables(args, genericType);
            }
            return genericType;
        }

        @Override
        final protected BeanD<?> getBean() {
            return parent.getBean();
        }

        @Override
        public final List<Class<?>> getGroupSequence() {
            return getBean().getGroupSequence();
        }
    }

    protected final Type genericType;

    private final Meta<E> meta;
    private final Set<ConstraintD<?>> constraints;

    protected ElementD(R reader) {
        super();
        Validate.notNull(reader, "reader");
        this.meta = reader.meta;
        this.genericType = reader.meta.getType();
        this.constraints = reader.getConstraints();
    }

    @Override
    public final boolean hasConstraints() {
        return !constraints.isEmpty();
    }

    @SuppressWarnings({ "unchecked", "rawtypes" })
    @Override
    public final Set<ConstraintDescriptor<?>> getConstraintDescriptors() {
        return (Set) constraints;
    }

    @Override
    public final ConstraintFinder findConstraints() {
        return new Finder(this);
    }

    public final ElementType getElementType() {
        return meta.getElementType();
    }

    public final E getTarget() {
        return meta.getHost();
    }

    public final Class<?> getDeclaringClass() {
        return meta.getDeclaringClass();
    }

    public abstract Type getGenericType();

    public abstract List<Class<?>> getGroupSequence();

    @Override
    public String toString() {
        return String.format("%s: %s", getClass().getSimpleName(), getTarget());
    }

    protected abstract BeanD<?> getBean();
}

@@ -3741,24 +3741,32 @@
 Name(), 
-getTarge
+meta.describeHos
 t());%0A  

improve toString