package com.fasterxml.jackson.databind;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;

/**
 * Tests to verify that most core Jackson components can be serialized
 * using default JDK serialization: this feature is useful for some
 * platforms, such as Android, where memory management is handled
 * much more aggressively.
 */
public class TestJDKSerialization extends BaseMapTest
{
    static class MyPojo {
        public int x;
        private int y;
        
        public MyPojo() { }
        public MyPojo(int x0, int y0) {
            x = x0;
            y = y0;
        }
        
        public int getY() { return y; }
        public void setY(int y) { this.y = y; }
    }

    /*
    /**********************************************************
    /* Tests for individual objects
    /**********************************************************
     */

    /* 18-Oct-2013, tatu: Not sure why, but looks like sharing the default
     *   ObjectMapper here can lead to strange unit test suite failures, so
     *   let's create a private copy for this class only.
     */
    private final ObjectMapper MAPPER = new ObjectMapper();
    
    public void testConfigs() throws IOException
    {
        byte[] base = jdkSerialize(MAPPER.getDeserializationConfig().getBaseSettings());
        assertNotNull(jdkDeserialize(base));

        // first things first: underlying BaseSettings
        
        DeserializationConfig origDC = MAPPER.getDeserializationConfig();
        SerializationConfig origSC = MAPPER.getSerializationConfig();
        byte[] dcBytes = jdkSerialize(origDC);
        byte[] scBytes = jdkSerialize(origSC);

        DeserializationConfig dc = jdkDeserialize(dcBytes);
        assertNotNull(dc);
        assertEquals(dc._deserFeatures, origDC._deserFeatures);
        SerializationConfig sc = jdkDeserialize(scBytes);
        assertNotNull(sc);
        assertEquals(sc._serFeatures, origSC._serFeatures);
    }

    public void testObjectWriter() throws IOException
    {
        ObjectWriter origWriter = MAPPER.writer();
        final String EXP_JSON = "{\"x\":2,\"y\":3}";
        final MyPojo p = new MyPojo(2, 3);
        assertEquals(EXP_JSON, origWriter.writeValueAsString(p));
        byte[] bytes = jdkSerialize(origWriter);
        ObjectWriter writer2 = jdkDeserialize(bytes);
        assertEquals(EXP_JSON, writer2.writeValueAsString(p));
    }
    
    public void testObjectReader() throws IOException
    {
        ObjectReader origReader = MAPPER.reader(MyPojo.class);
        final String JSON = "{\"x\":1,\"y\":2}";
        MyPojo p1 = origReader.readValue(JSON);
        assertEquals(2, p1.y);
        byte[] bytes = jdkSerialize(origReader);
        ObjectReader reader2 = jdkDeserialize(bytes);
        MyPojo p2 = reader2.readValue(JSON);
        assertEquals(2, p2.y);
    }

    public void testObjectMapper() throws IOException
    {
        final String EXP_JSON = "{\"x\":2,\"y\":3}";
        final MyPojo p = new MyPojo(2, 3);
        assertEquals(EXP_JSON, MAPPER.writeValueAsString(p));

        byte[] bytes = jdkSerialize(MAPPER);
        ObjectMapper mapper2 = jdkDeserialize(bytes);
        assertEquals(EXP_JSON, mapper2.writeValueAsString(p));
        MyPojo p2 = mapper2.readValue(EXP_JSON, MyPojo.class);
        assertEquals(p.x, p2.x);
        assertEquals(p.y, p2.y);
    }
    
    /*
    /**********************************************************
    /* Helper methods
    /**********************************************************
     */
    
    protected byte[] jdkSerialize(Object o) throws IOException
    {
        ByteArrayOutputStream bytes = new ByteArrayOutputStream(1000);
        ObjectOutputStream obOut = new ObjectOutputStream(bytes);
        obOut.writeObject(o);
        obOut.close();
        return bytes.toByteArray();
    }

    @SuppressWarnings("unchecked")
    protected <T> T jdkDeserialize(byte[] raw) throws IOException
    {
        ObjectInputStream objIn = new ObjectInputStream(new ByteArrayInputStream(raw));
        try {
            return (T) objIn.readObject();
        } catch (ClassNotFoundException e) {
            fail("Missing class: "+e.getMessage());
            return null;
        } finally {
            objIn.close();
        }
    }

}

@@ -207,16 +207,124 @@
 tream;%0A%0A
+import com.fasterxml.jackson.databind.type.TypeFactory;%0Aimport com.fasterxml.jackson.databind.util.LRUMap;%0A%0A
 /**%0A * T
@@ -3570,28 +3570,939 @@
 2.y);%0A    %7D%0A
+%0A
     
+public void testTypeFactory() throws Exception%0A    %7B%0A        TypeFactory orig = TypeFactory.defaultInstance();%0A        JavaType t = orig.constructType(JavaType.class);%0A        assertNotNull(t);%0A%0A        byte%5B%5D bytes = jdkSerialize(orig);%0A        TypeFactory result = jdkDeserialize(bytes);%0A        assertNotNull(result);%0A        t = orig.constructType(JavaType.class);%0A        assertEquals(JavaType.class, t.getRawClass());%0A    %7D%0A%0A    public void testLRUMap() throws Exception%0A    %7B%0A        LRUMap%3CString,Integer%3E map = new LRUMap%3CString,Integer%3E(32, 32);%0A        map.put(%22a%22, 1);%0A%0A        byte%5B%5D bytes = jdkSerialize(map);%0A        LRUMap%3CString,Integer%3E result = jdkDeserialize(bytes);%0A        // transient implementation, will be read as empty%0A        assertEquals(0, result.size());%0A%0A        // but should be possible to re-populate%0A        result.put(%22a%22, 2);%0A        assertEquals(1, result.size());%0A    %7D%0A
 %0A    /*%0A    

Add unit tests to try to tease out #767, no luck yet