Package org.apache.felix.scr.impl.helper

Source Code of org.apache.felix.scr.impl.helper.Annotations$Handler

/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements.  See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership.  The ASF licenses this file
* to you 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 org.apache.felix.scr.impl.helper;

import java.lang.reflect.Array;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.osgi.framework.Bundle;

public class Annotations
{
   
    static public <T> T toObject(Class<T> clazz, Map<String, Object> props, Bundle b, boolean supportsInterfaces )
    {    
        Map<String, Object> m = new HashMap<String, Object>();
       
        Method[] methods = clazz.getMethods();
        Map<String, Method> complexFields = new HashMap<String, Method>();
        for ( Method method: methods )
        {
            String name = method.getName();
            String key = fixup(name);
            Object raw = props.get(key);
            Class<?> returnType = method.getReturnType();
            Object cooked;
            if ( returnType.isInterface() || returnType.isAnnotation())
            {
                complexFields.put(key, method);
                continue;
            }
            if (returnType.isArray())
            {
                Class<?> componentType = returnType.getComponentType();
                if ( componentType.isInterface() || componentType.isAnnotation())
                {
                    complexFields.put(key, method);
                    continue;
                }
                cooked = coerceToArray(componentType, raw, b);
            }
            else
            {
                cooked = Coercions.coerce( returnType, raw, b );
            }
            m.put( name, cooked );
        }
        if (!complexFields.isEmpty())
        {
            if (!supportsInterfaces )
            {
            //error
                return null;//??
            }
            Map<String, List<Map<String, Object>>> nested = extractSubMaps(complexFields.keySet(), props);
            for (Map.Entry<String, Method> entry: complexFields.entrySet())
            {
                List<Map<String, Object>> proplist = nested.get(entry.getKey());
                Method method = entry.getValue();
                Class<?> returnType  = method.getReturnType();
                if (returnType.isArray())
                {
                    Class<?> componentType = returnType.getComponentType();
                    Object result = Array.newInstance(componentType, proplist.size());
                    for (int i = 0; i < proplist.size(); i++)
                    {
                        Map<String, Object> rawElement = proplist.get(i);
                        Object cooked = toObject(componentType, rawElement, b, supportsInterfaces);
                        Array.set(result, i, cooked);
                    }
                    m.put(method.getName(), result);
                }
                else
                {
                    if (!proplist.isEmpty())
                    {
                        Object cooked = toObject(returnType, proplist.get(0), b, supportsInterfaces);
                        m.put(method.getName(), cooked);
                    }
                }
            }
        }
       
        InvocationHandler h = new Handler(m);
        return (T) Proxy.newProxyInstance(clazz.getClassLoader(), new Class<?>[] { clazz }, h);
    }
   
    private static Map<String, List<Map<String, Object>>> extractSubMaps(Collection<String> keys, Map<String, Object> map)
    {
        Map<String, List<Map<String, Object>>> result = new HashMap<String, List<Map<String, Object>>>();
        //Form a regexp to recognize all the keys as prefixes in the map keys.
        StringBuilder b = new StringBuilder("(");
        for (String key: keys)
        {
            b.append(key).append("|");
        }
        b.deleteCharAt(b.length() -1);
        b.append(")\\.([0-9]*)\\.(.*)");
        Pattern p = Pattern.compile(b.toString());
        for (Map.Entry<String, Object> entry: map.entrySet())
        {
            String longKey = entry.getKey();
            Matcher m = p.matcher(longKey);
            if (m.matches())
            {
                String key = m.group(1);
                int index = Integer.parseInt(m.group(2));
                String subkey = m.group(3);
                List<Map<String, Object>> subMapsForKey = result.get(key);
                if (subMapsForKey == null)
                {
                    subMapsForKey = new ArrayList<Map<String, Object>>();
                    result.put(key, subMapsForKey);
                }
                //make sure there is room for the possible new submap
                for (int i = subMapsForKey.size(); i <= index; i++)
                {
                    subMapsForKey.add(new HashMap<String, Object>());                   
                }
                Map<String, Object> subMap = subMapsForKey.get(index);
                subMap.put(subkey, entry.getValue());
            }
        }
        return result;
    }

    private static Object coerceToArray(Class<?> componentType, Object raw, Bundle bundle)
    {
        if (raw == null)
        {
            return null;
        }
        if (raw.getClass().isArray())
        {
            int size = Array.getLength(raw);
            Object result = Array.newInstance(componentType, size);
            for (int i = 0; i < size; i++)
            {
                Object rawElement = Array.get(raw, i);
                Object cooked = Coercions.coerce(componentType, rawElement, bundle);
                Array.set(result, i, cooked);
            }
            return result;
        }
        if (raw instanceof Collection)
        {
            Collection raws = (Collection) raw;
            int size = raws.size();
            Object result = Array.newInstance(componentType, size);
            int i = 0;
            for (Object rawElement: raws)
            {
                Object cooked = Coercions.coerce(componentType, rawElement, bundle);
                Array.set(result, i++, cooked);
            }
            return result;

        }
        Object cooked = Coercions.coerce(componentType, raw, bundle);
        Object result = Array.newInstance(componentType, 1);
        Array.set(result, 0, cooked);
        return result;

    }
   
    private static final Pattern p = Pattern.compile("(\\$\\$)|(\\$)|(__)|(_)");
   
    static String fixup(String name)
    {
        Matcher m = p.matcher(name);
        StringBuffer b = new StringBuffer();
        while (m.find())
        {
            String replacement = "";//null;
            if (m.group(1) != null) replacement = "\\$";
            if (m.group(2) != null) replacement = "";
            if (m.group(3) != null) replacement = "_";
            if (m.group(4) != null) replacement = ".";
           
            m.appendReplacement(b, replacement);
        }
        m.appendTail(b);
        return b.toString();
    }

    private static class Handler implements InvocationHandler
    {
       
        private final Map<String, Object> values;
      
        public Handler(Map<String, Object> values)
        {
            this.values = values;
        }

        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable
        {
            return values.get(method.getName());
        }
       
    }

}
TOP

Related Classes of org.apache.felix.scr.impl.helper.Annotations$Handler

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.