ReflectionJsonParameterDispatcher.java

/***************************************************************************
   Copyright 2014 Emily Estes

   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 net.metanotion.util;


import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import net.metanotion.util.types.ObjectP;
import net.metanotion.util.types.Parser;

public final class ReflectionJsonParameterDispatcher<O> implements Dispatcher<O, Map.Entry<String,Iterable>> {
	private static final Logger logger = LoggerFactory.getLogger(ReflectionJsonParameterDispatcher.class);

	/** The type this dispatcher operates on. */
	private final Class<O> klass;
	private final Dispatcher<O, Map.Entry<String,Iterable>> disp;
	private final Dictionary<Class,Parser> parsers;
	private final Map<String, Params> methods = new HashMap<>();

	private interface Params {
		public Iterable parse(Iterable params) throws Exception;
	}

	private static final Params IDENTITY = new Params() {
		@Override public Iterable parse(final Iterable params) { return params; }
	};

	private static final class ParseParams implements Params {
		private final ArrayList<Parser> parsers = new ArrayList<>();
		public ParseParams(final Method m, final Dictionary<Class,Parser> typeDictionary) {
			final Class[] params = m.getParameterTypes();
			final Annotation[][] parameterAnnotations = m.getParameterAnnotations();
			int i = 0;
			for(Class c: params) {
				Parser p = ObjectP.INSTANCE;
				for(Annotation a: parameterAnnotations[i]) {
					if(a instanceof Json) { p = typeDictionary.get(c); }
				}
				parsers.add(p);
				i++;
			}
		}

		@Override public Iterable parse(final Iterable params) throws Exception {
			final ArrayList outParams = new ArrayList();
			int i = 0;
			for(Object o: params) {
				logger.debug("Json Params {} - {} - {}", i, o, parsers.get(i));
				outParams.add(parsers.get(i).parse(o));
				i++;
			}
			return outParams;
		}
	}

	public ReflectionJsonParameterDispatcher(final Class<O> klass,
															final Dictionary<Class, Parser> parsers,
															final Dispatcher<O, Map.Entry<String,Iterable>> disp) {
		this.klass = klass;
		this.parsers = parsers;
		this.disp = disp;

		final Field[] fields = klass.getFields();
		for(Field f: fields) { methods.put(f.getName(), IDENTITY); }

		final Method[] methodList = klass.getMethods();
		for(Method m: methodList) { methods.put(m.getName(), new ParseParams(m, parsers)); }
	}

	@Override public Message<O> dispatch(final Map.Entry<String,Iterable> data) {
		final String key = data.getKey();
		try {
			return disp.dispatch(new Pair<>(key, methods.get(key).parse(data.getValue())));
		} catch (Exception e) { throw new RuntimeException(e); }
	}
}