package com.fasterxml.jackson.databind.type;

import java.util.*;

import com.fasterxml.jackson.databind.*;

public class RecursiveTypeTest extends BaseMapTest
{
    // for [databind#1301]
    @SuppressWarnings("serial")
    static class HashTree<K, V> extends HashMap<K, HashTree<K, V>> { }

 // for [databind#938]
    public static interface Ability<T> { }

    public static final class ImmutablePair<L, R> implements Map.Entry<L, R>, Ability<ImmutablePair<L, R>> {
        public final L key;
        public final R value;

        public ImmutablePair(final L key, final R value) {
            this.key = key;
            this.value = value;
        }

        @Override
        public L getKey() {
            return key;
        }

        @Override
        public R getValue() {
            return value;
        }

        @Override
        public R setValue(final R value) {
            throw new UnsupportedOperationException();
        }
      
        static <L, R> ImmutablePair<L, R> of(final L left, final R right) {
            return new ImmutablePair<L, R>(left, right);
        }
    }

    // for [databind#1301]
    public void testRecursiveType()
    {
        TypeFactory tf = TypeFactory.defaultInstance();
        JavaType type = tf.constructType(HashTree.class);
        assertNotNull(type);
    }
    
    // for [databind#1301]
    @SuppressWarnings("serial")
    static class DataDefinition extends HashMap<String, DataDefinition> {
        public DataDefinition definition;
        public DataDefinition elements;
        public String regex;
        public boolean required;
        public String type;
    }
    
    private final ObjectMapper MAPPER = new ObjectMapper();

    // [databind#938]
    public void testRecursivePair() throws Exception
    {
        JavaType t = MAPPER.constructType(ImmutablePair.class);

        assertNotNull(t);
        assertEquals(ImmutablePair.class, t.getRawClass());

        List<ImmutablePair<String, Double>> list = new ArrayList<ImmutablePair<String, Double>>();
        list.add(ImmutablePair.of("Hello World!", 123d));
        String json = MAPPER.writeValueAsString(list);

        assertNotNull(json);

        // can not deserialize with current definition, however
    }

    // for [databind#1301]
    public void testJavaTypeToString() throws Exception
    {
        TypeFactory tf = objectMapper().getTypeFactory();
        String desc = tf.constructType(DataDefinition.class).toString();
        assertNotNull(desc);
        // could try comparing exact message, but since it's informational try looser:
        if (!desc.contains("map type")) {
            fail("Description should contain 'map type', did not: "+desc);
        }
        if (!desc.contains("recursive type")) {
            fail("Description should contain 'recursive type', did not: "+desc);
        }
    }
}

@@ -349,24 +349,227 @@
 ity%3CT%3E %7B %7D%0A%0A
+    // for %5Bdatabind#1647%5D%0A    static interface IFace%3CT%3E %7B%7D%0A%0A    // for %5Bdatabind#1647%5D%0A    static class Base implements IFace%3CSub%3E %7B %7D%0A%0A    // for %5Bdatabind#1647%5D%0A    static class Sub extends Base %7B %7D%0A%0A
     public s
@@ -3057,11 +3057,505 @@
  %7D%0A    %7D
+%0A%0A    // for %5Bdatabind#1647%5D%0A    public void testSuperClassWithReferencedJavaType() %7B%0A        TypeFactory tf = objectMapper().getTypeFactory();%0A        tf.constructType(Base.class); // must be constructed before sub to set the cache correctly%0A        JavaType subType = tf.constructType(Sub.class);%0A        // baseTypeFromSub should be a ResolvedRecursiveType in this test%0A        JavaType baseTypeFromSub = subType.getSuperClass();%0A        assertNotNull(baseTypeFromSub.getSuperClass());%0A    %7D
 %0A%7D%0A

Add test for #1647