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