/*
 * Orika - simpler, better and faster Java bean mapping
 *
 * Copyright (C) 2011-2013 Orika authors
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package ma.glasnost.orika;

import java.lang.reflect.ParameterizedType;

import ma.glasnost.orika.metadata.Property;
import ma.glasnost.orika.metadata.Type;
import ma.glasnost.orika.metadata.TypeFactory;

/**
 * CustomFilter provides the base implementation of Filter.
 * 
 * @author mattdeboer
 * 
 * @param <A>
 * @param <B>
 */
public abstract class CustomFilter<A, B> implements Filter<A, B> {
    
    private final Type<A> sourceType;
    private final Type<B> destinationType;
    
    /**
     * Constructs a new CustomFilter, inferring A-type and B-type from
     * the generic arguments.
     */
    public CustomFilter() {
        java.lang.reflect.Type genericSuperclass = getClass().getGenericSuperclass();
        if (genericSuperclass != null && genericSuperclass instanceof ParameterizedType) {
            ParameterizedType superType = (ParameterizedType) genericSuperclass;
            sourceType = TypeFactory.valueOf(superType.getActualTypeArguments()[0]);
            destinationType = TypeFactory.valueOf(superType.getActualTypeArguments()[1]);
        } else {
            throw new IllegalStateException("When you subclass the ConverterBase S and D type-parameters are required.");
        }
    }
    
    /* (non-Javadoc)
     * @see ma.glasnost.orika.MappedTypePair#getAType()
     */
    public Type<A> getAType() {
        return sourceType;
    }
    
    /* (non-Javadoc)
     * @see ma.glasnost.orika.MappedTypePair#getBType()
     */
    public Type<B> getBType() {
        return destinationType;
    }
    
    /* (non-Javadoc)
     * @see ma.glasnost.orika.Filter#appliesTo(ma.glasnost.orika.metadata.Property, ma.glasnost.orika.metadata.Property)
     */
    public boolean appliesTo(Property source, Property destination) {
        return sourceType.isAssignableFrom(source.getType()) && destinationType.isAssignableFrom(destination.getType());
    }
    
}

@@ -1201,100 +1201,538 @@
 , in
-ferring A-type and B-type from%0A     * the generic arguments.%0A     */%0A    public CustomFilter
+voking %7B@link #inferTypes%7D to get the A-type and B-type.%0A     */%0A    public CustomFilter() %7B%0A        MappedTypePair%3CA, B%3E types = inferTypes();%0A        sourceType = types.getAType();%0A        destinationType = types.getBType();%0A    %7D%0A%0A    /**%0A     * Infer A-type and B-type from the generic arguments. Subclasses may override this to%0A     * do their own inference.%0A     *%0A     * @return the A-type and B-type%0A     * @throws IllegalStateException if the types cannot be inferred%0A     */%0A    protected MappedTypePair%3CA, B%3E inferTypes
 () %7B
@@ -1921,16 +1921,22 @@
         
+final 
 Paramete
@@ -2008,28 +2008,84 @@
         
-sourceType =
+return new MappedTypePairHolder%3CA, B%3E(%0A                    (Type%3CA%3E)
  TypeFac
@@ -2135,17 +2135,17 @@
 ts()%5B0%5D)
-;
+,
 %0A       
@@ -2149,33 +2149,33 @@
         
-destinationType =
+        (Type%3CB%3E)
  TypeFac
@@ -2225,16 +2225,17 @@
 ts()%5B1%5D)
+)
 ;%0A      
@@ -3055,10 +3055,928 @@
  %7D%0A    %0A
+    /**%0A     * Simple implementation of MappedTypePair that holds the given pair of types.%0A     */%0A    protected static class MappedTypePairHolder%3CA, B%3E implements MappedTypePair%3CA, B%3E %7B%0A        private final Type%3CA%3E aType;%0A        private final Type%3CB%3E bType;%0A%0A        /**%0A         * Create a MappedTypePairHolder with the given types.%0A         *%0A         * @param aType the A-type%0A         * @param bType the B-type%0A         */%0A        public MappedTypePairHolder(Type%3CA%3E aType, Type%3CB%3E bType) %7B%0A            this.aType = aType;%0A            this.bType = bType;%0A        %7D%0A%0A        /* (non-Javadoc)%0A         * @see ma.glasnost.orika.MappedTypePair#getAType()%0A         */%0A        public Type%3CA%3E getAType() %7B%0A            return aType;%0A        %7D%0A%0A        /* (non-Javadoc)%0A         * @see ma.glasnost.orika.MappedTypePair#getBType()%0A         */%0A        public Type%3CB%3E getBType() %7B%0A            return bType;%0A        %7D%0A    %7D%0A
 %7D%0A

Allow subclasses to determine the A- and B-types.