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

org.glassfish.hk2.xml.internal.GeneratorUtilities Maven / Gradle / Ivy

/*
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 *
 * Copyright (c) 2017 Oracle and/or its affiliates. All rights reserved.
 *
 * The contents of this file are subject to the terms of either the GNU
 * General Public License Version 2 only ("GPL") or the Common Development
 * and Distribution License("CDDL") (collectively, the "License").  You
 * may not use this file except in compliance with the License.  You can
 * obtain a copy of the License at
 * https://glassfish.dev.java.net/public/CDDL+GPL_1_1.html
 * or packager/legal/LICENSE.txt.  See the License for the specific
 * language governing permissions and limitations under the License.
 *
 * When distributing the software, include this License Header Notice in each
 * file and include the License file at packager/legal/LICENSE.txt.
 *
 * GPL Classpath Exception:
 * Oracle designates this particular file as subject to the "Classpath"
 * exception as provided by Oracle in the GPL Version 2 section of the License
 * file that accompanied this code.
 *
 * Modifications:
 * If applicable, add the following below the License Header, with the fields
 * enclosed by brackets [] replaced by your own identifying information:
 * "Portions Copyright [year] [name of copyright owner]"
 *
 * Contributor(s):
 * If you wish your version of this file to be governed by only the CDDL or
 * only the GPL Version 2, indicate your decision by adding "[Contributor]
 * elects to include this software in this distribution under the [CDDL or GPL
 * Version 2] license."  If you don't indicate a single choice of license, a
 * recipient has the option to distribute your version of this file under
 * either the CDDL, the GPL Version 2 or to extend the choice of license to
 * its licensees as provided above.  However, if you add GPL Version 2 code
 * and therefore, elected the GPL Version 2 license, then the option applies
 * only if the new code is made subject to such option by the copyright
 * holder.
 */
package org.glassfish.hk2.xml.internal;

import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.xml.bind.annotation.XmlAnyAttribute;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlElementWrapper;
import javax.xml.bind.annotation.XmlElements;
import javax.xml.bind.annotation.XmlIDREF;
import javax.xml.bind.annotation.XmlValue;
import javax.xml.namespace.QName;

import org.glassfish.hk2.api.AnnotationLiteral;
import org.glassfish.hk2.xml.api.XmlService;
import org.glassfish.hk2.xml.api.annotations.PluralOf;
import org.glassfish.hk2.xml.internal.alt.AltAnnotation;
import org.glassfish.hk2.xml.internal.alt.AltClass;
import org.glassfish.hk2.xml.internal.alt.AltMethod;
import org.glassfish.hk2.xml.internal.alt.clazz.AnnotationAltAnnotationImpl;

/**
 * @author jwells
 *
 */
public class GeneratorUtilities {
    private final static String XML_VALUE_LOCAL_PART = "##XmlValue";
    public final static String XML_ANY_ATTRIBUTE_LOCAL_PART = "##XmlAnyAttribute";
    
    public static QName convertXmlRootElementName(AltAnnotation root, AltClass clazz) {
        String namespace = root.getStringValue("namespace");
        
        String rootName = root.getStringValue("name");
        
        if (!"##default".equals(rootName)) return QNameUtilities.createQName(namespace, rootName);
        
        String simpleName = clazz.getSimpleName();
        
        char asChars[] = simpleName.toCharArray();
        StringBuffer sb = new StringBuffer();
        
        boolean firstChar = true;
        boolean lastCharWasCapital = false;
        for (char asChar : asChars) {
            if (firstChar) {
                firstChar = false;
                if (Character.isUpperCase(asChar)) {
                    lastCharWasCapital = true;
                    sb.append(Character.toLowerCase(asChar));
                }
                else {
                    lastCharWasCapital = false;
                    sb.append(asChar);
                }
            }
            else {
                if (Character.isUpperCase(asChar)) {
                    if (!lastCharWasCapital) {
                        sb.append('-');
                    }
                    
                    sb.append(Character.toLowerCase(asChar));
                    
                    lastCharWasCapital = true;
                }
                else {
                    sb.append(asChar);
                    
                    lastCharWasCapital = false;
                }
            }
        }
        
        String localPart = sb.toString();
        
        return QNameUtilities.createQName(namespace, localPart);
    }
    
    private static boolean isSpecifiedReference(AltMethod method) {
        AltAnnotation customAnnotation = method.getAnnotation(XmlIDREF.class.getName());
        return (customAnnotation != null);
    }
    
    private static void checkOnlyOne(AltClass convertMe, AltMethod method, AltAnnotation aAnnotation, AltAnnotation bAnnotation) {
        if (aAnnotation != null && bAnnotation != null) {
            throw new IllegalArgumentException("The method " + method + " of " + convertMe + " has both the annotation " + aAnnotation + " and the annotation " +
              bAnnotation + " which is illegal");
        }
    }
    
    public static NameInformation getXmlNameMap(AltClass convertMe) {
        Map xmlNameMap = new LinkedHashMap();
        Set unmappedNames = new LinkedHashSet();
        Map addMethodToVariableMap = new LinkedHashMap();
        Map removeMethodToVariableMap = new LinkedHashMap();
        Map lookupMethodToVariableMap = new LinkedHashMap();
        Set referenceSet = new LinkedHashSet();
        Map> aliasMap = new LinkedHashMap>();
        XmlElementData valueData = null;
        XmlElementData xmlAnyAttributeData = null;
        
        boolean hasAnElement = false;
        for (AltMethod originalMethod : convertMe.getMethods()) {
            String setterVariable = Utilities.isSetter(originalMethod);
            if (setterVariable == null) {
                setterVariable = Utilities.isGetter(originalMethod);
                if (setterVariable == null) continue;
            }
            
            if (isSpecifiedReference(originalMethod)) {
                referenceSet.add(setterVariable);
            }
            
            AltAnnotation pluralOf = null;
            AltAnnotation xmlElement = originalMethod.getAnnotation(XmlElement.class.getName());
            AltAnnotation xmlElements = originalMethod.getAnnotation(XmlElements.class.getName());
            AltAnnotation xmlElementWrapper = originalMethod.getAnnotation(XmlElementWrapper.class.getName());
            AltAnnotation xmlAttribute = originalMethod.getAnnotation(XmlAttribute.class.getName());
            AltAnnotation xmlValue = originalMethod.getAnnotation(XmlValue.class.getName());
            AltAnnotation xmlAnyAttribute = originalMethod.getAnnotation(XmlAnyAttribute.class.getName());
            
            String xmlElementWrapperName = (xmlElementWrapper == null) ? null : xmlElementWrapper.getStringValue("name");
            if (xmlElementWrapperName != null && xmlElementWrapperName.isEmpty()) {
                xmlElementWrapperName = setterVariable;
            }
            
            checkOnlyOne(convertMe, originalMethod, xmlElement, xmlElements);
            checkOnlyOne(convertMe, originalMethod, xmlElement, xmlAttribute);
            checkOnlyOne(convertMe, originalMethod, xmlElements, xmlAttribute);
            checkOnlyOne(convertMe, originalMethod, xmlElement, xmlValue);
            checkOnlyOne(convertMe, originalMethod, xmlElements, xmlValue);
            checkOnlyOne(convertMe, originalMethod, xmlAttribute, xmlValue);
            checkOnlyOne(convertMe, originalMethod, xmlElement, xmlAnyAttribute);
            checkOnlyOne(convertMe, originalMethod, xmlElements, xmlAnyAttribute);
            checkOnlyOne(convertMe, originalMethod, xmlAttribute, xmlAnyAttribute);
            checkOnlyOne(convertMe, originalMethod, xmlValue, xmlAnyAttribute);
            
            if (xmlElements != null) {
                hasAnElement = true;
                
                // First add the actual method so it is known to the system
                pluralOf = originalMethod.getAnnotation(PluralOf.class.getName());
                    
                String defaultValue = Generator.JAXB_DEFAULT_DEFAULT;
                    
                xmlNameMap.put(setterVariable, new XmlElementData("", setterVariable, setterVariable, defaultValue, Format.ELEMENT, null, true, xmlElementWrapperName, false));
                    
                String aliasName = setterVariable;
                    
                AltAnnotation allXmlElements[] = xmlElements.getAnnotationArrayValue("value");
                List aliases = new ArrayList(allXmlElements.length);
                aliasMap.put(setterVariable, aliases);
                    
                for (AltAnnotation allXmlElement : allXmlElements) {
                    defaultValue = allXmlElement.getStringValue("defaultValue");
                    
                    String allXmlElementNamespace = allXmlElement.getStringValue("namespace");
                    String allXmlElementName = allXmlElement.getStringValue("name");
                    boolean allXmlElementRequired = allXmlElement.getBooleanValue("required");
                    AltClass allXmlElementType = (AltClass) allXmlElement.getAnnotationValues().get("type");
                    String allXmlElementTypeName = (allXmlElementType == null) ? null : allXmlElementType.getName() ;
                    boolean allXmlElementTypeInterface = (allXmlElementType == null) ? true : allXmlElementType.isInterface();
                        
                    if (Generator.JAXB_DEFAULT_STRING.equals(allXmlElementName)) {
                        throw new IllegalArgumentException("The name field of an XmlElement inside an XmlElements must have a specified name");
                    }
                    else {
                        aliases.add(new XmlElementData(
                                allXmlElementNamespace,
                                allXmlElementName,
                                aliasName,
                                defaultValue,
                                Format.ELEMENT,
                                allXmlElementTypeName,
                                allXmlElementTypeInterface,
                                xmlElementWrapperName,
                                allXmlElementRequired));
                    }
                }
            }
            else if (xmlElement != null) {
                hasAnElement = true;
                
                // Get the pluralOf from the method
                pluralOf = originalMethod.getAnnotation(PluralOf.class.getName());
                    
                String defaultValue = xmlElement.getStringValue("defaultValue");
                
                String namespace = xmlElement.getStringValue("namespace");
                String name = xmlElement.getStringValue("name");
                boolean required = xmlElement.getBooleanValue("required");
                    
                if (Generator.JAXB_DEFAULT_STRING.equals(name)) {
                    xmlNameMap.put(setterVariable, new XmlElementData(
                            namespace,
                            setterVariable,
                            setterVariable,
                            defaultValue,
                            Format.ELEMENT,
                            null,
                            true,
                            xmlElementWrapperName,
                            required));
                }
                else {
                    xmlNameMap.put(setterVariable, new XmlElementData(
                            namespace,
                            name,
                            name,
                            defaultValue,
                            Format.ELEMENT,
                            null,
                            true,
                            xmlElementWrapperName,
                            required));
                }
            }
            else if (xmlAttribute != null) {
                String namespace = xmlAttribute.getStringValue("namespace");
                String name = xmlAttribute.getStringValue("name");
                boolean required = xmlAttribute.getBooleanValue("required");
                
                if (Generator.JAXB_DEFAULT_STRING.equals(name)) {
                    xmlNameMap.put(setterVariable, new XmlElementData(
                            namespace,
                            setterVariable,
                            setterVariable,
                            Generator.JAXB_DEFAULT_DEFAULT,
                            Format.ATTRIBUTE,
                            null,
                            true,
                            xmlElementWrapperName,
                            required));
                }
                else {
                    xmlNameMap.put(setterVariable, new XmlElementData(
                            namespace,
                            name,
                            name,
                            Generator.JAXB_DEFAULT_DEFAULT,
                            Format.ATTRIBUTE,
                            null,
                            true,
                            xmlElementWrapperName,
                            required));
                }
            }
            else if (xmlValue != null) {
                if (valueData != null) {
                    throw new IllegalArgumentException("There may be only one XmlValue method on " + convertMe);
                }
                
                valueData = new XmlElementData(
                        XmlService.DEFAULT_NAMESPACE,
                        XML_VALUE_LOCAL_PART,
                        XML_VALUE_LOCAL_PART,
                        null,
                        Format.VALUE,
                        null,
                        false,
                        xmlElementWrapperName,
                        true);
                xmlNameMap.put(setterVariable, valueData);
            }
            else if (xmlAnyAttribute != null) {
                if (xmlAnyAttributeData != null) {
                    throw new IllegalArgumentException("There may be only one XmlAnyAttribute method on " + convertMe);
                }
                
                xmlAnyAttributeData = new XmlElementData(
                        XmlService.DEFAULT_NAMESPACE,
                        XML_ANY_ATTRIBUTE_LOCAL_PART,
                        XML_ANY_ATTRIBUTE_LOCAL_PART,
                        null,
                        Format.ATTRIBUTE,
                        null,
                        false,
                        xmlElementWrapperName,
                        false);
                xmlNameMap.put(setterVariable, xmlAnyAttributeData);       
            }
            else {
                unmappedNames.add(setterVariable);
            }
            
            if (pluralOf == null) pluralOf = new AnnotationAltAnnotationImpl(new PluralOfDefault(), null);
            
            String unDecapitalizedVariable = originalMethod.getName().substring(3);
            
            addMethodToVariableMap.put(getMethodName(MethodType.ADD, unDecapitalizedVariable, pluralOf), setterVariable);
            removeMethodToVariableMap.put(getMethodName(MethodType.REMOVE, unDecapitalizedVariable, pluralOf), setterVariable);
            lookupMethodToVariableMap.put(getMethodName(MethodType.LOOKUP, unDecapitalizedVariable, pluralOf), setterVariable);
        }
        
        if (valueData != null && hasAnElement) {
            throw new IllegalArgumentException("A bean cannot both have XmlElements and XmlValue methods in " + convertMe);
        }
        
        Set noXmlElementNames = new LinkedHashSet();
        for (String unmappedName : unmappedNames) {
            if (!xmlNameMap.containsKey(unmappedName)) {
                noXmlElementNames.add(unmappedName);
            }
        }
        
        return new NameInformation(xmlNameMap, noXmlElementNames,
                addMethodToVariableMap,
                removeMethodToVariableMap,
                lookupMethodToVariableMap,
                referenceSet,
                aliasMap,
                valueData);
    }
    
    private static String getMethodName(MethodType methodType, String unDecapitalizedVariable, AltAnnotation instructions) {
        String retVal;
        
        switch (methodType) {
            case ADD:
                retVal = instructions.getStringValue("add");
                break;
            case REMOVE:
                retVal = instructions.getStringValue("remove");
                break;
            case LOOKUP:
                retVal = instructions.getStringValue("lookup");
                break;
            default:
                throw new AssertionError("Only ADD, REMOVE and LOOKUP supported");
        }
        
        if (!PluralOf.USE_NORMAL_PLURAL_PATTERN.equals(retVal)) {
            // We got the specific name for the method, overrides any algorithm
            return retVal;
        }
        
        String pluralOf = instructions.getStringValue("value");
        if (!PluralOf.USE_NORMAL_PLURAL_PATTERN.equals(pluralOf)) {
            // We got a specific name for the singular, use it
            switch (methodType) {
            case ADD:
                return JAUtilities.ADD + pluralOf;
            case REMOVE:
                return JAUtilities.REMOVE + pluralOf;
            case LOOKUP:
                return JAUtilities.LOOKUP + pluralOf;
            default:
                throw new AssertionError("Only add, remove and lookup supported");
            }
        }
        
        // Do the algorithm
        if (unDecapitalizedVariable.endsWith("s")) {
            unDecapitalizedVariable = unDecapitalizedVariable.substring(0, unDecapitalizedVariable.length() - 1);
        }
        
        switch (methodType) {
        case ADD:
            return JAUtilities.ADD + unDecapitalizedVariable;
        case REMOVE:
            return JAUtilities.REMOVE + unDecapitalizedVariable;
        case LOOKUP:
            return JAUtilities.LOOKUP + unDecapitalizedVariable;
        default:
            throw new AssertionError("Only add, remove and lookup supported");
        }
        
    }
    
    private static final class PluralOfDefault extends AnnotationLiteral implements PluralOf {
        private static final long serialVersionUID = 4358923840720264176L;

        /* (non-Javadoc)
         * @see org.glassfish.hk2.xml.api.annotations.PluralOf#value()
         */
        @Override
        public String value() {
            return PluralOf.USE_NORMAL_PLURAL_PATTERN;
        }

        /* (non-Javadoc)
         * @see org.glassfish.hk2.xml.api.annotations.PluralOf#add()
         */
        @Override
        public String add() {
            return PluralOf.USE_NORMAL_PLURAL_PATTERN;
        }

        /* (non-Javadoc)
         * @see org.glassfish.hk2.xml.api.annotations.PluralOf#remove()
         */
        @Override
        public String remove() {
            return PluralOf.USE_NORMAL_PLURAL_PATTERN;
        }

        /* (non-Javadoc)
         * @see org.glassfish.hk2.xml.api.annotations.PluralOf#lookup()
         */
        @Override
        public String lookup() {
            return PluralOf.USE_NORMAL_PLURAL_PATTERN;
        }
        
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy