001package gu.sql2java;
002import java.lang.reflect.ParameterizedType;
003import java.lang.reflect.Type;
004import java.util.ArrayList;
005import java.util.Collection;
006import java.util.HashMap;
007import java.util.List;
008import java.util.Map;
009import java.util.Map.Entry;
010
011import static com.google.common.base.Preconditions.*;
012/**
013 * 
014 * @author guyadong
015 *
016 * @param <L> left type
017 * @param <R> right type
018 */
019public interface IBeanConverter<L,R> {
020
021    /**
022     * Default abstract implementation of {@link IBeanConverter}<br>
023     * 
024     * @author guyadong
025     *
026     * @param <L> left type
027     * @param <R> right type
028     */
029    public static abstract class  AbstractHandle <L,R>implements IBeanConverter<L, R> {
030        /** L type  */
031        protected final Class<?> leftType;
032        /** R type  */
033        protected final Class<?> rightType;
034        private static Class<?> getRawClass(Type type){
035            if(type instanceof Class<?>){
036                return (Class<?>) type;
037            } else if(type instanceof ParameterizedType){
038                return getRawClass(((ParameterizedType) type).getRawType());
039            } else{
040                throw new IllegalArgumentException("invalid type");
041            }
042        }
043        public AbstractHandle() {
044            Type superClass = getClass().getGenericSuperclass();
045            this.leftType = getRawClass(((ParameterizedType) superClass).getActualTypeArguments()[0]);
046            this.rightType = getRawClass(((ParameterizedType) superClass).getActualTypeArguments()[1]);
047        }
048        public AbstractHandle(Class<L> leftClass,Class<R> rightClass) {
049            this.leftType = checkNotNull(leftClass,"leftClass is null");
050            this.rightType = checkNotNull(rightClass,"rightClass is null");
051        }
052        /** 
053         * copy right TO left, left and right must not be null
054         * @param left
055         * @param right
056         */
057        protected abstract void doFromRight(L left, R right);
058        /** 
059         * copy left TO right, left and right must not be null 
060         * @param left
061         * @param right
062         */
063        protected abstract void doToRight(L left, R right);
064        /**
065         *  Creates a new  L instance by calling constructor with an empty argument list<br>
066         *  you must override the method if the L class haven't default constructor.
067         * @return
068         */
069        @SuppressWarnings("unchecked")
070        protected L newInstanceL(){ return (L) newInstance(this.leftType); }
071        /**
072         *  Creates a new R instance by calling constructor with an empty argument list<br>
073         *  you must override the method if the R class haven't default constructor.
074         * @return
075         */
076        @SuppressWarnings("unchecked")
077        protected R newInstanceR(){ return (R) newInstance(this.rightType); }
078        
079        protected  static<T> T newInstance(Class<T>clazz){
080            try {
081                return (T) clazz.newInstance();
082            } catch (InstantiationException e) {
083                throw new RuntimeException(e);
084            } catch (IllegalAccessException e) {
085                throw new RuntimeException(e);
086            }
087        }
088        @Override
089        public L fromRight(L left, R right) {
090            if(null != right && null != left){
091                this.doFromRight(left, right);
092            }            
093            return left;
094        }
095
096        @Override
097        public R toRight(L left, R right) {
098            if(null != left && null != right){
099                this.doToRight(left, right);
100            }
101            return right;
102        }
103
104        @Override
105        public L fromRight(R bean) {
106            return null == bean? null : fromRight(newInstanceL(),bean);
107        }
108
109        @Override
110        public R toRight(L bean) {
111            return null == bean? null : toRight(bean,newInstanceR());
112        }
113
114        @Override
115        public R[] toRight(L[] lefts, R[] rights) {
116            if(null != lefts && null != rights){
117                if( lefts.length != rights.length){
118                    throw new IllegalArgumentException("mismatched length between left and right array");
119                }
120                for(int i=0;i<lefts.length;++i){
121                    this.toRight(lefts[i],rights[i]);
122                }
123            }
124            return rights;
125        }
126
127        @Override
128        public L[] fromRight(L[] lefts, R[] rights) {
129            if(null != rights && null != lefts){
130                if( lefts.length != rights.length){
131                    throw new IllegalArgumentException("mismatched length between left and right array");
132                }
133                for(int i=0;i<lefts.length;++i){
134                    this.fromRight(lefts[i],rights[i]);
135                }
136            }
137            return lefts;
138        }
139        
140        @SuppressWarnings("unchecked")
141        @Override
142        public R[] toRight(L[] lefts) {
143            R[] rights = null;
144            if(null != lefts){
145                rights = (R[])java.lang.reflect.Array.newInstance(rightType,lefts.length) ;
146                for(int i=0;i<lefts.length;++i){
147                    rights[i] = toRight(lefts[i]);
148                }
149            }
150            return rights;
151        }
152
153        @SuppressWarnings("unchecked")
154        @Override
155        public L[] fromRight(R[] rights) {
156            L[] lefts = null;
157            if(null != rights){
158                lefts = (L[])java.lang.reflect.Array.newInstance(leftType,rights.length) ;
159                for(int i=0;i<rights.length;++i){
160                    lefts[i] = fromRight(rights[i]);
161                }
162            }
163            return lefts;
164        }
165
166        @Override
167        public List<R> toRight(Collection<L> beans) {
168            if(null==beans){
169                return null;
170            }
171            ArrayList<R> rights = new ArrayList<R>(beans.size());
172            for(L g:beans){
173                rights.add(this.toRight(g));
174            }
175            return rights;
176        }
177
178        @Override
179        public List<L> fromRight(Collection<R> beans) {
180            if(null==beans){
181                return null;
182            }
183            ArrayList<L> lefts = new ArrayList<L>(beans.size());
184            for(R n:beans){
185                lefts.add(this.fromRight(n));
186            }
187            return lefts;
188        }
189
190        @Override
191        public List<R> toRight(List<L> lefts, List<R> rights) {
192            if(null != lefts && null != rights){
193                if( lefts.size() != rights.size()){
194                    throw new IllegalArgumentException("mismatched length between left and right list");
195                }
196                for(int i=0;i<lefts.size();++i){
197                    this.toRight(lefts.get(i),rights.get(i));
198                }
199            }
200            return rights;
201        }
202
203        @Override
204        public List<L> fromRight(List<L> lefts, List<R> rights) {
205            if(null != rights && null != lefts){
206                if( lefts.size() != rights.size()){
207                    throw new IllegalArgumentException("mismatched length between left and right list");
208                }
209                for(int i=0;i<lefts.size();++i){
210                    this.fromRight(lefts.get(i),rights.get(i));
211                }
212            }
213            return lefts;
214        }
215
216        @Override
217        public List<R> toRight(List<L> lefts) {
218            List<R> rights = null;
219            if(null != lefts ){
220                rights  = new ArrayList<>();
221                for(L l:lefts){
222                    rights.add(toRight(l));
223                }
224            }
225            return rights;    
226        }
227
228        @Override
229        public List<L> fromRight(List<R> rights) {
230            List<L> lefts = null;
231            if(null != rights ){
232                lefts  = new ArrayList<>();
233                for(R r:rights){
234                    lefts.add(fromRight(r));
235                }
236            }
237            return lefts;            
238        }
239        @Override
240        public<V> Map<R,V> toRightKey(Map<L,V> lmap) {
241            if(null == lmap){
242                return null;
243            }
244            HashMap<R,V> rmap = new HashMap<R,V>(16);
245            for(Entry<L, V> entry:lmap.entrySet()){
246                rmap.put(this.toRight(entry.getKey()),entry.getValue());
247            }
248            return rmap;
249        }
250        @Override
251        public<K> Map<K,R> toRightValue(Map<K,L> lmap) {
252            if(null == lmap){
253                return null;
254            }
255            HashMap<K, R> rmap = new HashMap<K, R>(16);
256            for(Entry<K, L> entry:lmap.entrySet()){
257                rmap.put(entry.getKey(), this.toRight(entry.getValue()));
258            }
259            return rmap;
260        }
261        @Override
262        public<V> Map<L,V> fromRightKey(Map<R,V> rmap) {
263            if(null == rmap){
264                return null;
265            }
266            HashMap<L,V> lmap = new HashMap<L,V>(16);
267            for(Entry<R, V> entry:rmap.entrySet()){
268                lmap.put(this.fromRight(entry.getKey()),entry.getValue());
269            }
270            return lmap;
271        }
272        @Override
273        public<K> Map<K,L> fromRightValue(Map<K,R> rmap) {
274            if(null == rmap){
275                return null;
276            }
277            HashMap<K, L> lmap = new HashMap<K, L>(16);
278            for(Entry<K, R> entry:rmap.entrySet()){
279                lmap.put(entry.getKey(), this.fromRight(entry.getValue()));
280            }
281            return lmap;
282        }
283        @Override
284        public Map<R,R> toRight(Map<L,L> lmap) {
285            if(null == lmap){
286                return null;
287            }
288            HashMap<R,R> rmap = new HashMap<R,R>(16);
289            for(Entry<L, L> entry:lmap.entrySet()){
290                rmap.put(this.toRight(entry.getKey()),this.toRight(entry.getValue()));
291            }
292            return rmap;
293        }
294        @Override
295        public Map<L,L> fromRight(Map<R,R> rmap) {
296            if(null == rmap){
297                return null;
298            }
299            HashMap<L,L> lmap = new HashMap<L,L>(16);
300            for(Entry<R, R> entry:rmap.entrySet()){
301                lmap.put(this.fromRight(entry.getKey()),this.fromRight(entry.getValue()));
302            }
303            return lmap;
304        }
305    }
306
307    /**
308     * copy right TO left
309     * @param left
310     * @param right
311     * @return left,or new instance if left is null
312     */
313    public L fromRight(L left, R right);
314    
315    /**
316     * copy left TO right
317     * @param left
318     * @param right
319     * @return right,or new instance if right is null
320     */
321    public R toRight(L left, R right);
322    /**
323     * return an new instance converted from R bean
324     * @param bean
325     * @return L bean
326     */
327    public L fromRight(R bean);
328    /**
329     * return an new instance converted from L bean
330     * @param bean
331     * @return R bean
332     */
333    public R toRight( L bean);
334    /**
335     * copy rights TO lefts
336     * @param lefts
337     * @param rights
338     * @return lefts,or new array if lefts is null
339     */
340    public L[] fromRight(L[] lefts,R[] rights);
341    /**
342     * copy lefts TO rights
343     * @param lefts
344     * @param rights
345     * @return rights,or new array if rights is null
346     */
347    public R[] toRight(L[] lefts,R[] rights);
348    /**
349     * return an new array converted from R beans
350     * @param beans
351     * @return L bean array
352     */
353    public L[] fromRight(R[] beans);
354    /**
355     * an new array converted from L beans
356     * @param beans
357     * @return R bean array
358     */
359    public R[] toRight(L[] beans);
360    /**
361     * copy rights TO lefts
362     * @param lefts
363     * @param rights
364     * @return lefts,or new array if lefts is null
365     */
366    public List<L> fromRight(List<L> lefts,List<R> rights);
367    /**
368     * copy lefts TO rights
369     * @param lefts
370     * @param rights
371     * @return rights,or new array if rights is null
372     */
373    public List<R> toRight(List<L> lefts,List<R> rights);
374    /**
375     * return an new list converted from R beans
376     * @param beans
377     * @return L bean list
378     */
379    public List<L> fromRight(List<R> beans);
380    /**
381     * return an new list converted from L beans
382     * @param beans
383     * @return R bean list
384     */
385    public List<R> toRight(List<L> beans);
386    /**
387     * return an new list converted from R beans
388     * @param beans
389     * @return L bean list
390     */
391    public List<L> fromRight(Collection<R> beans);
392    /**
393     * an new list converted from L beans
394     * @param beans
395     * @return R bean list
396     */
397    public List<R> toRight(Collection<L> beans);
398    
399    /**
400     * return an new map with R key converted from map with L key
401     * @param lmap
402     * @return Map with R key
403     */
404    public <V> Map<R,V> toRightKey(Map<L,V> lmap);
405    /**
406     * return an new map with R value converted from map with L value
407     * @param lmap
408     * @return Map with R value
409     */
410    public <K> Map<K,R> toRightValue(Map<K,L> lmap);
411    /**
412     * return an new map with L key converted from map with R key
413     * @param rmap
414     * @return Map with L key
415     */
416    public <V> Map<L,V> fromRightKey(Map<R,V> rmap);
417    /**
418     * return an new map with L value converted from map with R value
419     * @param rmap
420     * @return Map with L value
421     */
422    public <K> Map<K,L> fromRightValue(Map<K,R> rmap);
423    /**
424     * an new map with R key and  R value converted from map with L key and L value
425     * @param lmap
426     * @return Map with R key and value
427     */
428    public Map<R,R> toRight(Map<L,L> lmap);
429    /**
430     * return an new map with L key and  L value converted from map with R key and R value
431     * @param rmap
432     * @return Map with L key and value
433     */
434    public Map<L,L> fromRight(Map<R,R> rmap);
435}