Package org.cojen.util

Source Code of org.cojen.util.AnnotationDescParser

/*
*  Copyright 2007-2010 Brian S O'Neill
*
*  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.
*/

/*
* Copyright 2006 Amazon Technologies, Inc. or its affiliates.
* Amazon, Amazon.com and Carbonado are trademarks or registered trademarks
* of Amazon Technologies, Inc. or its affiliates.  All rights reserved.
*
* 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 org.cojen.util;

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

import org.cojen.classfile.TypeDesc;
import org.cojen.classfile.attribute.Annotation;

// Import the tags.
import static org.cojen.util.AnnotationDescPrinter.*;

/**
* Parses an annotation descriptor String to a Cojen Annotation definition.
*
* @author Brian S O'Neill
* @see AnnotationDescPrinter
* @since 2.1
*/
public class AnnotationDescParser {
    private final String mStr;

    private int mPos;

    /**
     * @param annotationString annotation to parse
     */
    public AnnotationDescParser(String annotationString) {
        mStr = annotationString;
    }

    /**
     * Parses the given annotation, returning the root annotation that received
     * the results.
     *
     * @param rootAnnotation root annotation
     * @return root annotation
     * @throws IllegalArgumentExcecption if annotation is malformed
     */
    public Annotation parse(Annotation rootAnnotation) {
        mPos = 0;

        if (parseTag() != TAG_ANNOTATION) {
            throw error("Malformed");
        }

        TypeDesc rootAnnotationType = parseTypeDesc();

        if (rootAnnotation == null) {
            rootAnnotation = buildRootAnnotation(rootAnnotationType);
        } else if (!rootAnnotationType.equals(rootAnnotation.getType())) {
            throw new IllegalArgumentException
                ("Annotation type of \"" + rootAnnotationType +
                 "\" does not match expected type of \"" + rootAnnotation.getType());
        }

        parseAnnotation(rootAnnotation, rootAnnotationType);

        return rootAnnotation;
    }

    /**
     * Override this method if a root annotation is not provided, as it must be
     * built after parsing the root annotation type. By default, this method
     * throws UnsupportedOperationException.
     */
    protected Annotation buildRootAnnotation(TypeDesc rootAnnotationType) {
        throw new UnsupportedOperationException();
    }

    private void parseAnnotation(Annotation dest, TypeDesc annType) {
        while (true) {
            try {
                if (mStr.charAt(mPos) == ';') {
                    mPos++;
                    break;
                }
            } catch (IndexOutOfBoundsException e) {
                error("Missing terminator");
            }

            if (mPos >= mStr.length()) {
                break;
            }

            String propName = parseName();
            char propTag = peekTag();

            Annotation.MemberValue mv;
            if (propTag == TAG_ARRAY) {
                mPos++;
                mv = parseArray(dest, peekTag(), parseTypeDesc());
            } else {
                mv = parseProperty(dest, propTag, parseTypeDesc());
            }

            dest.putMemberValue(propName, mv);
        }
    }

    private Annotation.MemberValue parseArray(Annotation dest, char compTag, TypeDesc compType) {
        List<Annotation.MemberValue> mvList = new ArrayList<Annotation.MemberValue>();
        while (true) {
            try {
                if (mStr.charAt(mPos) == ';') {
                    mPos++;
                    break;
                }
            } catch (IndexOutOfBoundsException e) {
                error("Missing terminator");
            }

            mvList.add(parseProperty(dest, compTag, compType));
        }
        Annotation.MemberValue[] mvArray = new Annotation.MemberValue[mvList.size()];
        return dest.makeMemberValue(mvList.toArray(mvArray));
    }

    private Annotation.MemberValue parseProperty(Annotation dest, char propTag, TypeDesc propType)
    {
        Annotation.MemberValue mv;

        try {
            if (propTag == TAG_STRING) {
                StringBuilder b = new StringBuilder();
                while (true) {
                    char c = mStr.charAt(mPos++);
                    if (c == ';') {
                        break;
                    }
                    if (c == '\\') {
                        c = mStr.charAt(mPos++);
                    }
                    b.append(c);
                }
                mv = dest.makeMemberValue(b.toString());
            } else if (propTag == TAG_BOOLEAN) {
                mv = dest.makeMemberValue(mStr.charAt(mPos++) != '0');
            } else if (propTag == TAG_CHAR) {
                mv = dest.makeMemberValue(mStr.charAt(mPos++));
            } else if (propTag == TAG_ANNOTATION) {
                Annotation propAnn = dest.makeAnnotation();
                propAnn.setType(propType);
                parseAnnotation(propAnn, propType);
                mv = dest.makeMemberValue(propAnn);
            } else if (propTag == TAG_CLASS) {
                mv = dest.makeMemberValue(parseTypeDesc());
            } else {
                int endPos = nextTerminator();
                String valueStr = mStr.substring(mPos, endPos);

                switch (propTag) {
                default:
                    throw error("Invalid tag");

                case TAG_BYTE: {
                    mv = dest.makeMemberValue(Byte.parseByte(valueStr));
                    break;
                }

                case TAG_SHORT: {
                    mv = dest.makeMemberValue(Short.parseShort(valueStr));
                    break;
                }

                case TAG_INT: {
                    mv = dest.makeMemberValue(Integer.parseInt(valueStr));
                    break;
                }

                case TAG_LONG: {
                    mv = dest.makeMemberValue(Long.parseLong(valueStr));
                    break;
                }

                case TAG_FLOAT: {
                    mv = dest.makeMemberValue(Float.parseFloat(valueStr));
                    break;
                }

                case TAG_DOUBLE: {
                    mv = dest.makeMemberValue(Double.parseDouble(valueStr));
                    break;
                }

                case TAG_ENUM: {
                    mv = dest.makeMemberValue(propType, valueStr);
                    break;
                }
                }

                mPos = endPos + 1;
            }
        } catch (IndexOutOfBoundsException e) {
            throw error("Invalid property value");
        }

        return mv;
    }

    private TypeDesc parseTypeDesc() {
        try {
            int endPos;

            switch (mStr.charAt(mPos)) {
            default:
                throw error("Invalid tag");

            case TAG_ARRAY:
                mPos++;
                return parseTypeDesc().toArrayType();

            case TAG_STRING:
                mPos++;
                return TypeDesc.STRING;

            case TAG_CLASS:
                mPos++;
                return TypeDesc.forClass(Class.class);

            case TAG_ANNOTATION:
                mPos++;
                return parseTypeDesc();

            case TAG_ENUM:
                mPos++;
                endPos = nextTerminator();
                int dot = mStr.lastIndexOf('.', endPos);
                if (dot < mPos) {
                    throw error("Invalid enumeration");
                }
                TypeDesc type = TypeDesc.forClass(mStr.substring(mPos, dot));
                mPos = dot + 1;
                return type;

            case TAG_BOOLEAN:
            case TAG_BYTE:
            case TAG_SHORT:
            case TAG_CHAR:
            case TAG_INT:
            case TAG_LONG:
            case TAG_FLOAT:
            case TAG_DOUBLE:
            case TAG_VOID:
                endPos = mPos + 1;
                break;

            case TAG_OBJECT:
                endPos = nextTerminator() + 1;
                break;
            }

            TypeDesc type = TypeDesc.forDescriptor(mStr.substring(mPos, endPos));
            mPos = endPos;

            return type;
        } catch (IndexOutOfBoundsException e) {
            throw error("Invalid type descriptor");
        }
    }

    private char peekTag() {
        char tag = parseTag();
        mPos--;
        return tag;
    }

    private char parseTag() {
        try {
            return mStr.charAt(mPos++);
        } catch (IndexOutOfBoundsException e) {
            throw error("Too short");
        }
    }

    private String parseName() {
        int index = mStr.indexOf('=', mPos);
        if (index < 0) {
            throw error("Incomplete assignment");
        }
        String name = mStr.substring(mPos, index);
        mPos = index + 1;
        return name;
    }

    private int nextTerminator() {
        int index = mStr.indexOf(';', mPos);
        if (index < 0) {
            throw error("Missing terminator");
        }
        return index;
    }

    private IllegalArgumentException error(String message) {
        message = "Illegal annotation descriptor: " + message +
            " at position " + mPos + " of " + mStr;
        return new IllegalArgumentException(message);
    }
}
TOP

Related Classes of org.cojen.util.AnnotationDescParser

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.