Fix [Issue-14]; parent classes of mix-in annotations were being ignored for methods, fields

diff --git a/release-notes/VERSION b/release-notes/VERSION
index 177281b..cc4001a 100644
--- a/release-notes/VERSION
+++ b/release-notes/VERSION
@@ -13,6 +13,9 @@
    (reported by Steven S)
   * [Issue-11] JsonParser.getValueAsLong() returning int, not long
    (reported by Daniel L)
+  * [Issue-14]: Annotations were not included from parent classes of
+    mix-in classes
+   (reported by @guillaup)
   * [JACKSON-829] Custom serializers not working for List<String> properties,
     @JsonSerialize(contentUsing)
    (reported by James R)
diff --git a/src/mapper/java/org/codehaus/jackson/map/introspect/AnnotatedClass.java b/src/mapper/java/org/codehaus/jackson/map/introspect/AnnotatedClass.java
index 837d9ab..3e36020 100644
--- a/src/mapper/java/org/codehaus/jackson/map/introspect/AnnotatedClass.java
+++ b/src/mapper/java/org/codehaus/jackson/map/introspect/AnnotatedClass.java
@@ -416,7 +416,7 @@
         if (_mixInResolver != null) {
             Class<?> mixin = _mixInResolver.findMixInClassFor(Object.class);
             if (mixin != null) {
-                _addMethodMixIns(methodFilter, _memberMethods, mixin, mixins);
+                _addMethodMixIns(_class, methodFilter, _memberMethods, mixin, mixins);
             }
         }
 
@@ -610,7 +610,7 @@
     {
         // first, mixIns, since they have higher priority then class methods
         if (mixInCls != null) {
-            _addMethodMixIns(methodFilter, methods, mixInCls, mixIns);
+            _addMethodMixIns(cls, methodFilter, methods, mixInCls, mixIns);
         }
 
         if (cls == null) { // just so caller need not check when passing super-class
@@ -650,26 +650,32 @@
         }
     }
 
-    protected void _addMethodMixIns(MethodFilter methodFilter, AnnotatedMethodMap methods,
+    protected void _addMethodMixIns(Class<?> targetClass,
+            MethodFilter methodFilter, AnnotatedMethodMap methods,
             Class<?> mixInCls, AnnotatedMethodMap mixIns)
     {
-        for (Method m : mixInCls.getDeclaredMethods()) {
-            if (!_isIncludableMethod(m, methodFilter)) {
-                continue;
-            }
-            AnnotatedMethod am = methods.find(m);
-            /* Do we already have a method to augment (from sub-class
-             * that will mask this mixIn)? If so, add if visible
-             * without masking (no such annotation)
-             */
-            if (am != null) {
-                _addMixUnders(m, am);
-                /* Otherwise will have precedence, but must wait
-                 * until we find the real method (mixIn methods are
-                 * just placeholder, can't be called)
+        List<Class<?>> parents = new ArrayList<Class<?>>();
+        parents.add(mixInCls);
+        ClassUtil.findSuperTypes(mixInCls, targetClass, parents);
+        for (Class<?> mixin : parents) {        
+            for (Method m : mixin.getDeclaredMethods()) {
+                if (!_isIncludableMethod(m, methodFilter)) {
+                    continue;
+                }
+                AnnotatedMethod am = methods.find(m);
+                /* Do we already have a method to augment (from sub-class
+                 * that will mask this mixIn)? If so, add if visible
+                 * without masking (no such annotation)
                  */
-            } else {
-                mixIns.add(_constructMethod(m));
+                if (am != null) {
+                    _addMixUnders(m, am);
+                    /* Otherwise will have precedence, but must wait
+                     * until we find the real method (mixIn methods are
+                     * just placeholder, can't be called)
+                     */
+                } else {
+                    mixIns.add(_constructMethod(m));
+                }
             }
         }
     }
@@ -710,7 +716,7 @@
             if (_mixInResolver != null) {
                 Class<?> mixin = _mixInResolver.findMixInClassFor(c);
                 if (mixin != null) {
-                    _addFieldMixIns(mixin, fields);
+                    _addFieldMixIns(parent, mixin, fields);
                 }
             }
         }
@@ -721,22 +727,28 @@
      * into already collected actual fields (from introspected classes and their
      * super-classes)
      */
-    protected void _addFieldMixIns(Class<?> mixin, Map<String,AnnotatedField> fields)
+    protected void _addFieldMixIns(Class<?> targetClass, Class<?> mixInCls,
+            Map<String,AnnotatedField> fields)
     {
-        for (Field mixinField : mixin.getDeclaredFields()) {
-            /* there are some dummy things (static, synthetic); better
-             * ignore
-             */
-            if (!_isIncludableField(mixinField)) {
-                continue;
-            }
-            String name = mixinField.getName();
-            // anything to mask? (if not, quietly ignore)
-            AnnotatedField maskedField = fields.get(name);
-            if (maskedField != null) {
-                for (Annotation a : mixinField.getDeclaredAnnotations()) {
-                    if (_annotationIntrospector.isHandled(a)) {
-                        maskedField.addOrOverride(a);
+        List<Class<?>> parents = new ArrayList<Class<?>>();
+        parents.add(mixInCls);
+        ClassUtil.findSuperTypes(mixInCls, targetClass, parents);
+        for (Class<?> mixin : parents) {
+            for (Field mixinField : mixin.getDeclaredFields()) {
+                /* there are some dummy things (static, synthetic); better
+                 * ignore
+                 */
+                if (!_isIncludableField(mixinField)) {
+                    continue;
+                }
+                String name = mixinField.getName();
+                // anything to mask? (if not, quietly ignore)
+                AnnotatedField maskedField = fields.get(name);
+                if (maskedField != null) {
+                    for (Annotation a : mixinField.getDeclaredAnnotations()) {
+                        if (_annotationIntrospector.isHandled(a)) {
+                            maskedField.addOrOverride(a);
+                        }
                     }
                 }
             }
diff --git a/src/test/org/codehaus/jackson/map/mixins/TestMixinInheritance.java b/src/test/org/codehaus/jackson/map/mixins/TestMixinInheritance.java
index 206f225..28c967f 100644
--- a/src/test/org/codehaus/jackson/map/mixins/TestMixinInheritance.java
+++ b/src/test/org/codehaus/jackson/map/mixins/TestMixinInheritance.java
@@ -25,7 +25,30 @@
         public int ido;
     }
 
-    public void testMixinInheritance() throws IOException
+    static class Beano2 {
+        public int getIdo() { return 13; }
+        public String getNameo() { return "Bill"; }
+    }
+
+    static abstract class BeanoMixinSuper2 extends Beano2 {
+        @Override
+        @JsonProperty("name")
+        public abstract String getNameo();
+    }
+
+    static abstract class BeanoMixinSub2 extends BeanoMixinSuper2 {
+        @Override
+        @JsonProperty("id")
+        public abstract int getIdo();
+    }
+    
+    /*
+    /**********************************************************
+    /* Unit tests
+    /**********************************************************
+     */    
+
+    public void testMixinFieldInheritance() throws IOException
     {
         ObjectMapper mapper = new ObjectMapper();
         mapper.getSerializationConfig().addMixInAnnotations(Beano.class, BeanoMixinSub.class);
@@ -35,4 +58,15 @@
         assertTrue(result.containsKey("id"));
         assertTrue(result.containsKey("name"));
     }
+
+    public void testMixinMethodInheritance() throws IOException
+    {
+        ObjectMapper mapper = new ObjectMapper();
+        mapper.getSerializationConfig().addMixInAnnotations(Beano2.class, BeanoMixinSub2.class);
+        Map<String,Object> result;
+        result = writeAndMap(mapper, new Beano2());
+        assertEquals(2, result.size());
+        assertTrue(result.containsKey("id"));
+        assertTrue(result.containsKey("name"));
+    }
 }