// Path: src/main/java/ru/vyarus/java/generics/resolver/context/container/ExplicitTypeVariable.java
// public class ExplicitTypeVariable implements Type {
// 
//     private final String name;
//     private final TypeVariable declarationSource;
//     private final Type[] bounds;
// 
//     public ExplicitTypeVariable(final TypeVariable variable) {
//         this.name = variable.getName();
//         this.declarationSource = variable;
//         this.bounds = variable.getBounds();
//     }
// 
//     public ExplicitTypeVariable(final String name) {
//         this.name = name;
//         this.declarationSource = null;
//         this.bounds = new Type[]{Object.class};
//     }
// 
//     /**
//      * @return variable name
//      */
//     public String getName() {
//         return name;
//     }
// 
//     /**
//      * @return original (source) type variable or null
//      */
//     public TypeVariable getDeclarationSource() {
//         return declarationSource;
//     }
// 
//     /**
//      * @return variable bound (Object when no known bound)
//      */
//     public Type[] getBounds() {
//         return Arrays.copyOf(bounds, bounds.length);
//     }
// 
//     @Override
//     public String toString() {
//         return name;
//     }
// 
//     @Override
//     public boolean equals(final Object o) {
//         if (this == o) {
//             return true;
//         }
//         if (!(o instanceof ExplicitTypeVariable)) {
//             return false;
//         }
// 
//         final ExplicitTypeVariable that = (ExplicitTypeVariable) o;
// 
//         if (!name.equals(that.name)) {
//             return false;
//         }
//         if (declarationSource != null
//                 ? !declarationSource.equals(that.declarationSource) : that.declarationSource != null) {
//             return false;
//         }
//         return Arrays.equals(bounds, that.bounds);
//     }
// 
//     @Override
//     public int hashCode() {
//         int result = name.hashCode();
//         result = 31 * result + (declarationSource != null ? declarationSource.hashCode() : 0);
//         result = 31 * result + Arrays.hashCode(bounds);
//         return result;
//     }
// }


import ru.vyarus.java.generics.resolver.context.container.ExplicitTypeVariable;
import java.lang.reflect.Type;
import java.util.LinkedHashMap;
import java.util.Map;
package ru.vyarus.java.generics.resolver.util.map;



/**
 * Special map to use with {@link ru.vyarus.java.generics.resolver.util.TypeToStringUtils} in order to see generic
 * name in the resulted string. For example, {@code List<T> instead of List<Object>}.
 *
 * @author Vyacheslav Rusakov
 * @since 13.05.2018
 */
public class PrintableGenericsMap extends LinkedHashMap<String, Type> {

    public PrintableGenericsMap() {
        // default
    }

    public PrintableGenericsMap(final Map<? extends String, ? extends Type> m) {
        super(m);
    }

    @Override
    public Type get(final Object key) {
        // always Object for unknown generic name
        final Type res = super.get(key);
// Path: src/main/java/ru/vyarus/java/generics/resolver/context/container/ExplicitTypeVariable.java
// public class ExplicitTypeVariable implements Type {
// 
//     private final String name;
//     private final TypeVariable declarationSource;
//     private final Type[] bounds;
// 
//     public ExplicitTypeVariable(final TypeVariable variable) {
//         this.name = variable.getName();
//         this.declarationSource = variable;
//         this.bounds = variable.getBounds();
//     }
// 
//     public ExplicitTypeVariable(final String name) {
//         this.name = name;
//         this.declarationSource = null;
//         this.bounds = new Type[]{Object.class};
//     }
// 
//     /**
//      * @return variable name
//      */
//     public String getName() {
//         return name;
//     }
// 
//     /**
//      * @return original (source) type variable or null
//      */
//     public TypeVariable getDeclarationSource() {
//         return declarationSource;
//     }
// 
//     /**
//      * @return variable bound (Object when no known bound)
//      */
//     public Type[] getBounds() {
//         return Arrays.copyOf(bounds, bounds.length);
//     }
// 
//     @Override
//     public String toString() {
//         return name;
//     }
// 
//     @Override
//     public boolean equals(final Object o) {
//         if (this == o) {
//             return true;
//         }
//         if (!(o instanceof ExplicitTypeVariable)) {
//             return false;
//         }
// 
//         final ExplicitTypeVariable that = (ExplicitTypeVariable) o;
// 
//         if (!name.equals(that.name)) {
//             return false;
//         }
//         if (declarationSource != null
//                 ? !declarationSource.equals(that.declarationSource) : that.declarationSource != null) {
//             return false;
//         }
//         return Arrays.equals(bounds, that.bounds);
//     }
// 
//     @Override
//     public int hashCode() {
//         int result = name.hashCode();
//         result = 31 * result + (declarationSource != null ? declarationSource.hashCode() : 0);
//         result = 31 * result + Arrays.hashCode(bounds);
//         return result;
//     }
// }


// Path: src/main/java/ru/vyarus/java/generics/resolver/util/map/PrintableGenericsMap.java
import ru.vyarus.java.generics.resolver.context.container.ExplicitTypeVariable;
import java.lang.reflect.Type;
import java.util.LinkedHashMap;
import java.util.Map;

package ru.vyarus.java.generics.resolver.util.map;



/**
 * Special map to use with {@link ru.vyarus.java.generics.resolver.util.TypeToStringUtils} in order to see generic
 * name in the resulted string. For example, {@code List<T> instead of List<Object>}.
 *
 * @author Vyacheslav Rusakov
 * @since 13.05.2018
 */
public class PrintableGenericsMap extends LinkedHashMap<String, Type> {

    public PrintableGenericsMap() {
        // default
    }

    public PrintableGenericsMap(final Map<? extends String, ? extends Type> m) {
        super(m);
    }

    @Override
    public Type get(final Object key) {
        // always Object for unknown generic name
        final Type res = super.get(key);
        return res == null ? new ExplicitTypeVariable((String) key) : res;