All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.wink.common.internal.type.TypeParser Maven / Gradle / Ivy

The newest version!
/*
 * 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.wink.common.internal.type;

import java.util.ArrayList;
import java.util.List;
import java.util.StringTokenizer;

/**
 * Simple recursive-descent parser for parsing canonical {@link JavaType}
 * representations and constructing type instances.
 * 
 * @author tatu
 * @since 1.5
 */
public class TypeParser {
    final TypeFactory _factory;

    public TypeParser(TypeFactory f) {
        _factory = f;
    }

    public JavaType parse(String canonical) throws IllegalArgumentException {
        canonical = canonical.trim();
        MyTokenizer tokens = new MyTokenizer(canonical);
        JavaType type = parseType(tokens);
        // must be end, now
        if (tokens.hasMoreTokens()) {
            throw _problem(tokens, "Unexpected tokens after complete type");
        }
        return type;
    }

    protected JavaType parseType(MyTokenizer tokens) throws IllegalArgumentException {
        if (!tokens.hasMoreTokens()) {
            throw _problem(tokens, "Unexpected end-of-string");
        }
        Class base = findClass(tokens.nextToken(), tokens);
        // either end (ok, non generic type), or generics
        if (tokens.hasMoreTokens()) {
            String token = tokens.nextToken();
            if ("<".equals(token)) {
                return _factory._fromParameterizedClass(base, parseTypes(tokens));
            }
            // can be comma that separates types, or closing '>'
            tokens.pushBack(token);
        }
        return _factory._fromClass(base, null);
    }

    protected List parseTypes(MyTokenizer tokens) throws IllegalArgumentException {
        ArrayList types = new ArrayList();
        while (tokens.hasMoreTokens()) {
            types.add(parseType(tokens));
            if (!tokens.hasMoreTokens())
                break;
            String token = tokens.nextToken();
            if (">".equals(token))
                return types;
            if (!",".equals(token)) {
                throw _problem(tokens, "Unexpected token '" + token + "', expected ',' or '>')");
            }
        }
        throw _problem(tokens, "Unexpected end-of-string");
    }

    protected Class findClass(String className, MyTokenizer tokens) {
        try {
            /* [JACKSON-350]: Default Class.forName() won't work too well; context class loader
             *    seems like slightly better choice
             */
            //          return Class.forName(className);
            ClassLoader loader = Thread.currentThread().getContextClassLoader();
            return Class.forName(className, true, loader);
        } catch (Exception e) {
            if (e instanceof RuntimeException) {
                throw (RuntimeException)e;
            }
            throw _problem(tokens, "Can not locate class '" + className + "', problem: " + e.getMessage());
        }
    }

    protected IllegalArgumentException _problem(MyTokenizer tokens, String msg) {
        return new IllegalArgumentException("Failed to parse type '" + tokens.getAllInput()
            + "' (remaining: '"
            + tokens.getRemainingInput()
            + "'): "
            + msg);
    }

    final static class MyTokenizer extends StringTokenizer {
        protected final String _input;

        protected int _index;

        protected String _pushbackToken;

        public MyTokenizer(String str) {
            super(str, "<,>", true);
            _input = str;
        }

        @Override
        public boolean hasMoreTokens() {
            return (_pushbackToken != null) || super.hasMoreTokens();
        }

        @Override
        public String nextToken() {
            String token;
            if (_pushbackToken != null) {
                token = _pushbackToken;
                _pushbackToken = null;
            } else {
                token = super.nextToken();
            }
            _index += token.length();
            return token;
        }

        public void pushBack(String token) {
            _pushbackToken = token;
            _index -= token.length();
        }

        public String getAllInput() {
            return _input;
        }

        public String getUsedInput() {
            return _input.substring(0, _index);
        }

        public String getRemainingInput() {
            return _input.substring(_index);
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy