001// ***************************************************************************************************************************
002// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements.  See the NOTICE file *
003// * distributed with this work for additional information regarding copyright ownership.  The ASF licenses this file        *
004// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance            *
005// * with the License.  You may obtain a copy of the License at                                                              *
006// *                                                                                                                         *
007// *  http://www.apache.org/licenses/LICENSE-2.0                                                                             *
008// *                                                                                                                         *
009// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an  *
010// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the License for the        *
011// * specific language governing permissions and limitations under the License.                                              *
012// ***************************************************************************************************************************
013package org.apache.juneau.xml;
014
015import java.util.*;
016
017import org.apache.juneau.*;
018import org.apache.juneau.xml.annotation.*;
019
020/**
021 * Metadata on bean properties specific to the XML serializers and parsers pulled from the {@link Xml @Xml} annotation
022 * on the bean property.
023 */
024public class XmlBeanPropertyMeta extends BeanPropertyMetaExtended {
025
026   private Namespace namespace = null;
027   private XmlFormat xmlFormat = XmlFormat.DEFAULT;
028   private String childName;
029
030   /**
031    * Constructor.
032    * 
033    * @param bpm The metadata of the bean property of this additional metadata.
034    */
035   public XmlBeanPropertyMeta(BeanPropertyMeta bpm) {
036      super(bpm);
037
038      if (bpm.getField() != null)
039         findXmlInfo(bpm.getField().getAnnotation(Xml.class));
040      if (bpm.getGetter() != null)
041         findXmlInfo(bpm.getGetter().getAnnotation(Xml.class));
042      if (bpm.getSetter() != null)
043         findXmlInfo(bpm.getSetter().getAnnotation(Xml.class));
044
045      if (namespace == null)
046         namespace = bpm.getBeanMeta().getClassMeta().getExtendedMeta(XmlClassMeta.class).getNamespace();
047   }
048
049   /**
050    * Returns the XML namespace associated with this bean property.
051    * 
052    * <p>
053    * Namespace is determined in the following order of {@link Xml#prefix() @Xml.prefix()} annotation:
054    * <ol>
055    *    <li>Bean property field.
056    *    <li>Bean getter.
057    *    <li>Bean setter.
058    *    <li>Bean class.
059    *    <li>Bean package.
060    *    <li>Bean superclasses.
061    *    <li>Bean superclass packages.
062    *    <li>Bean interfaces.
063    *    <li>Bean interface packages.
064    * </ol>
065    * 
066    * @return The namespace associated with this bean property, or <jk>null</jk> if no namespace is associated with it.
067    */
068   public Namespace getNamespace() {
069      return namespace;
070   }
071
072   /**
073    * Returns the XML format of this property from the {@link Xml#format} annotation on this bean property.
074    * 
075    * @return The XML format, or {@link XmlFormat#DEFAULT} if annotation not specified.
076    */
077   protected XmlFormat getXmlFormat() {
078      return xmlFormat;
079   }
080
081   /**
082    * Returns the child element of this property from the {@link Xml#childName} annotation on this bean property.
083    * 
084    * @return The child element, or <jk>null</jk> if annotation not specified.
085    */
086   protected String getChildName() {
087      return childName;
088   }
089
090   private void findXmlInfo(Xml xml) {
091      if (xml == null)
092         return;
093      BeanPropertyMeta bpm = getBeanPropertyMeta();
094      ClassMeta<?> cmProperty = bpm.getClassMeta();
095      ClassMeta<?> cmBean = bpm.getBeanMeta().getClassMeta();
096      String name = bpm.getName();
097
098      List<Xml> xmls = bpm.findAnnotations(Xml.class);
099      List<XmlSchema> schemas = bpm.findAnnotations(XmlSchema.class);
100      namespace = XmlUtils.findNamespace(xmls, schemas);
101
102      if (xmlFormat == XmlFormat.DEFAULT)
103         xmlFormat = xml.format();
104
105      boolean isCollection = cmProperty.isCollectionOrArray();
106
107      String cen = xml.childName();
108      if ((! cen.isEmpty()) && (! isCollection))
109         throw new BeanRuntimeException(cmProperty.getInnerClass(),
110            "Annotation error on property ''{0}''.  @Xml.childName can only be specified on collections and arrays.", name);
111
112      if (xmlFormat == XmlFormat.COLLAPSED) {
113         if (isCollection) {
114            if (cen.isEmpty())
115               cen = cmProperty.getExtendedMeta(XmlClassMeta.class).getChildName();
116            if (cen == null || cen.isEmpty())
117               cen = cmProperty.getElementType().getDictionaryName();
118            if (cen == null || cen.isEmpty())
119               cen = name;
120         } else {
121            throw new BeanRuntimeException(cmBean.getInnerClass(),
122               "Annotation error on property ''{0}''.  @Xml.format=COLLAPSED can only be specified on collections and arrays.", name);
123         }
124         if (cen.isEmpty() && isCollection)
125            cen = cmProperty.getDictionaryName();
126      }
127
128      if (! cen.isEmpty())
129         childName = cen;
130   }
131}