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 * 024 * <h5 class='section'>See Also:</h5><ul> 025 * <li class='link'><a class="doclink" href="../../../../index.html#jm.XmlDetails">XML Details</a> 026 * </ul> 027 */ 028public class XmlBeanPropertyMeta extends ExtendedBeanPropertyMeta { 029 030 /** 031 * Default instance. 032 */ 033 public static final XmlBeanPropertyMeta DEFAULT = new XmlBeanPropertyMeta(); 034 035 private Namespace namespace = null; 036 private XmlFormat xmlFormat = XmlFormat.DEFAULT; 037 private String childName; 038 private final XmlMetaProvider xmlMetaProvider; 039 040 /** 041 * Constructor. 042 * 043 * @param bpm The metadata of the bean property of this additional metadata. 044 * @param mp XML metadata provider (for finding information about other artifacts). 045 */ 046 public XmlBeanPropertyMeta(BeanPropertyMeta bpm, XmlMetaProvider mp) { 047 super(bpm); 048 this.xmlMetaProvider = mp; 049 050 bpm.forEachAnnotation(Xml.class, x -> true, x -> findXmlInfo(x, mp)); 051 052 if (namespace == null) 053 namespace = mp.getXmlClassMeta(bpm.getBeanMeta().getClassMeta()).getNamespace(); 054 } 055 056 private XmlBeanPropertyMeta() { 057 super(null); 058 this.xmlMetaProvider = null; 059 } 060 061 /** 062 * Returns the XML namespace associated with this bean property. 063 * 064 * <p> 065 * Namespace is determined in the following order of {@link Xml#prefix() @Xml(prefix)} annotation: 066 * <ol> 067 * <li>Bean property field. 068 * <li>Bean getter. 069 * <li>Bean setter. 070 * <li>Bean class. 071 * <li>Bean package. 072 * <li>Bean superclasses. 073 * <li>Bean superclass packages. 074 * <li>Bean interfaces. 075 * <li>Bean interface packages. 076 * </ol> 077 * 078 * @return The namespace associated with this bean property, or <jk>null</jk> if no namespace is associated with it. 079 */ 080 public Namespace getNamespace() { 081 return namespace; 082 } 083 084 /** 085 * Returns the XML format of this property from the {@link Xml#format} annotation on this bean property. 086 * 087 * @return The XML format, or {@link XmlFormat#DEFAULT} if annotation not specified. 088 */ 089 public XmlFormat getXmlFormat() { 090 return xmlFormat; 091 } 092 093 /** 094 * Returns the child element of this property from the {@link Xml#childName} annotation on this bean property. 095 * 096 * @return The child element, or <jk>null</jk> if annotation not specified. 097 */ 098 public String getChildName() { 099 return childName; 100 } 101 102 private void findXmlInfo(Xml xml, AnnotationProvider mp) { 103 if (xml == null) 104 return; 105 BeanPropertyMeta bpm = getBeanPropertyMeta(); 106 ClassMeta<?> cmProperty = bpm.getClassMeta(); 107 ClassMeta<?> cmBean = bpm.getBeanMeta().getClassMeta(); 108 String name = bpm.getName(); 109 110 List<Xml> xmls = bpm.getAllAnnotationsParentFirst(Xml.class); 111 List<XmlSchema> schemas = bpm.getAllAnnotationsParentFirst(XmlSchema.class); 112 namespace = XmlUtils.findNamespace(xmls, schemas); 113 114 if (xmlFormat == XmlFormat.DEFAULT) 115 xmlFormat = xml.format(); 116 117 boolean isCollection = cmProperty.isCollectionOrArray(); 118 119 String cen = xml.childName(); 120 if ((! cen.isEmpty()) && (! isCollection)) 121 throw new BeanRuntimeException(cmProperty.getInnerClass(), 122 "Annotation error on property ''{0}''. @Xml.childName can only be specified on collections and arrays.", name); 123 124 if (xmlFormat == XmlFormat.COLLAPSED) { 125 if (isCollection) { 126 if (cen.isEmpty() && xmlMetaProvider != null) 127 cen = xmlMetaProvider.getXmlClassMeta(cmProperty).getChildName(); 128 if (cen == null || cen.isEmpty()) 129 cen = cmProperty.getElementType().getDictionaryName(); 130 if (cen == null || cen.isEmpty()) 131 cen = name; 132 } else { 133 throw new BeanRuntimeException(cmBean.getInnerClass(), 134 "Annotation error on property ''{0}''. @Xml.format=COLLAPSED can only be specified on collections and arrays.", name); 135 } 136 if (cen.isEmpty() && isCollection) 137 cen = cmProperty.getDictionaryName(); 138 } 139 140 if (! cen.isEmpty()) 141 childName = cen; 142 } 143}