package com.fasterxml.jackson.databind.mixins;

import java.io.*;

import com.fasterxml.jackson.annotation.*;

import com.fasterxml.jackson.databind.*;

public class TestMixinDeserForCreators
    extends BaseMapTest
{
    /*
    /**********************************************************
    /* Helper bean classes
    /**********************************************************
     */

    static class BaseClass
    {
        protected String _a;

        public BaseClass(String a) {
            _a = a+"...";
        }

        private BaseClass(String value, boolean dummy) {
            _a = value;
        }

        public static BaseClass myFactory(String a) {
            return new BaseClass(a+"X", true);
        }
    }

    static class BaseClassWithPrivateCtor
    {
        protected String _a;
        private BaseClassWithPrivateCtor(String a) {
            _a = a+"...";
        }

    }

    /**
     * Mix-in class that will effectively suppresses String constructor,
     * and marks a non-auto-detectable static method as factory method
     * as a creator.
     *<p>
     * Note that method implementations are not used for anything; but
     * we have to a class: interface won't do, as they can't have
     * constructors or static methods.
     */
    static class MixIn
    {
        @JsonIgnore protected MixIn(String s) { }

        @JsonCreator
        static BaseClass myFactory(String a) { return null; }
    }

    static class MixInForPrivate
    {
        @JsonCreator MixInForPrivate(String s) { }
    }

    static class StringWrapper {
        String _value;
        private StringWrapper(String s, boolean foo) { _value = s; }

        @SuppressWarnings("unused")
        private static StringWrapper create(String str) {
            return new StringWrapper(str, false);
        }
    }

    abstract static class StringWrapperMixIn {
        @JsonCreator static StringWrapper create(String str) { return null; }
    }

    // [databind#2020]
    @JsonIgnoreProperties("size")
    abstract class MyPairMixIn8 { // with and without <Long, String>
         @JsonCreator
         public Pair2020 with(@JsonProperty("value0") Object value0, 
                   @JsonProperty("value1") Object value1) 
         {
             // body does not matter, only signature
             return null;
         }
    }    

    static class Pair2020 {
        final int x, y;

        private Pair2020(int x0, int y0) {
            x = x0;
            y = y0;
        }

        @JsonCreator
        static Pair2020 with(Object x0, Object y0) {
//        static Pair2020 with(@JsonProperty("value0") Object x0, @JsonProperty("value1")Object y0) {
        return new Pair2020(((Number) x0).intValue(),
                    ((Number) y0).intValue());
        }
    }

    /*
    /**********************************************************
    /* Unit tests
    /**********************************************************
     */

    public void testForConstructor() throws IOException
    {
        ObjectMapper m = new ObjectMapper();
        m.addMixIn(BaseClassWithPrivateCtor.class, MixInForPrivate.class);
        BaseClassWithPrivateCtor result = m.readValue("\"?\"", BaseClassWithPrivateCtor.class);
        assertEquals("?...", result._a);
    }

    public void testForFactoryAndCtor() throws IOException
    {
        ObjectMapper m = new ObjectMapper();
        BaseClass result;

        // First: test default behavior: should use constructor
        result = m.readValue("\"string\"", BaseClass.class);
        assertEquals("string...", result._a);

        // Then with simple mix-in: should change to use the factory method
        m = new ObjectMapper();
        m.addMixIn(BaseClass.class, MixIn.class);
        result = m.readValue("\"string\"", BaseClass.class);
        assertEquals("stringX", result._a);
    }

    public void testFactoryDelegateMixIn() throws IOException
    {
        ObjectMapper m = new ObjectMapper();
        m.addMixIn(StringWrapper.class, StringWrapperMixIn.class);
        StringWrapper result = m.readValue("\"a\"", StringWrapper.class);
        assertEquals("a", result._value);
    }

    // [databind#2020]
    /*
    public void testFactoryPropertyMixin() throws Exception
    {
        ObjectMapper objectMapper = new ObjectMapper();
        objectMapper.addMixIn(Pair2020.class, MyPairMixIn8.class);

        String doc = aposToQuotes( "{'value0' : 456, 'value1' : 789}");
        Pair2020 pair2 = objectMapper.readValue(doc, Pair2020.class);
        assertEquals(456, pair2.x);
        assertEquals(789, pair2.y);
    }
    */
}

@@ -1983,374 +1983,8 @@
 20%5D%0A
-    @JsonIgnoreProperties(%22size%22)%0A    abstract class MyPairMixIn8 %7B // with and without %3CLong, String%3E%0A         @JsonCreator%0A         public Pair2020 with(@JsonProperty(%22value0%22) Object value0, %0A                   @JsonProperty(%22value1%22) Object value1) %0A         %7B%0A             // body does not matter, only signature%0A             return null;%0A         %7D%0A    %7D    %0A%0A
     
@@ -2126,37 +2126,16 @@
      %7D%0A%0A
-        @JsonCreator%0A
         
@@ -2183,25 +2183,295 @@
 ) %7B%0A
-//        static 
+            return new Pair2020(((Number) x0).intValue(),%0A                    ((Number) y0).intValue());%0A        %7D%0A    %7D%0A%0A    @JsonIgnoreProperties(%22size%22)%0A    static class MyPairMixIn8 %7B // with and without %3CLong, String%3E%0A         @JsonCreator%0A         static TestMixinDeserForCreators.
 Pair
@@ -2511,19 +2511,42 @@
  Object 
-x0,
+value0,%0A                  
  @JsonPr
@@ -2561,26 +2561,40 @@
 value1%22)
+ 
 Object 
-y0)
+value1)%0A        
  %7B%0A     
@@ -2600,101 +2600,80 @@
     
+  
-return new Pair2020(((Number) x0).intValue(),%0A                    ((Number) y0).intValue())
+   // body does not matter, only signature%0A             return null
 ;%0A
+ 
     
@@ -4078,23 +4078,16 @@
 d#2020%5D%0A
-    /*%0A
     publ
@@ -4488,17 +4488,10 @@
 ;%0A    %7D%0A
-    */%0A
 %7D%0A

Enable #2020 test