Java tutorial
/** * Copyright 2013 Autentia Real Business Solution S.L. * * 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 com.autentia.xml.namespace; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.xml.bind.JAXBContext; import javax.xml.bind.JAXBIntrospector; import javax.xml.namespace.QName; import java.util.regex.Pattern; import static org.apache.commons.lang3.StringUtils.isNotBlank; public class QNameBuilder { private static final Logger logger = LoggerFactory.getLogger(QNameBuilder.class); private static final Pattern BY_DOTS = Pattern.compile("\\."); private static final Pattern VOWELS = Pattern.compile("[aeiou]"); private static final QName EMPTY_Q_NAME = new QName("", "", ""); private final QNameMemory memory; public QNameBuilder(QNameMemory memory) { this.memory = memory; } public QName buildFor(Class<?> classType) { return discoverQNameAndCachesIt(classType, "", "", memory.forSingleTypes()); } public QName buildForCollectionOf(Class<?> clazz) { return discoverQNameAndCachesIt(clazz, "Collection", "cll", memory.forCollectionTypes()); } private QName discoverQNameAndCachesIt(Class<?> classType, String classTypeNameSuffix, String prefixSuffix, QNamesCache cache) { QName qName = cache.getQNameFor(classType); if (qName == null) { qName = discoverQNameFromJaxb(classType); final String localPart = (isNotBlank(qName.getLocalPart()) ? qName.getLocalPart() : discoverLocalPartFor(classType)) + classTypeNameSuffix; final String namespaceUri = isNotBlank(qName.getNamespaceURI()) ? qName.getNamespaceURI() : discoverNamespaceUriFor(classType, localPart); final String prefix = isNotBlank(qName.getPrefix()) ? qName.getPrefix() : discoverPrefixFor(classType, prefixSuffix); qName = new QName(namespaceUri, localPart, prefix); cache.putQNameFor(classType, qName); } return qName; } private QName discoverQNameFromJaxb(Class<?> classType) { QName qName = null; try { final JAXBIntrospector jaxbIntrospector = JAXBContext.newInstance(classType).createJAXBIntrospector(); qName = jaxbIntrospector.getElementName(classType.getConstructor().newInstance()); } catch (Exception e) { // Add e to the logger message because JAXB Exceptions has a lot of information in the toString(). // and some loggers implementations just print the getMessage(); logger.warn("Cannot discover QName from JAXB annotations for class: " + classType.getName() + ". Preparing generic QName." + e, e); } if (qName == null) { // Could be null if getElementName returned null, or a exception was thrown. return EMPTY_Q_NAME; } return qName; } private String discoverNamespaceUriFor(Class<?> classType, String localPart) { final String[] classNameSections = BY_DOTS.split(classType.getName()); return "http://www." + classNameSections[1] + '.' + classNameSections[0] + "/schema/" + localPart; } private String discoverLocalPartFor(Class<?> classType) { final String classTypeName = classType.getSimpleName(); return classTypeName.substring(0, 1).toLowerCase() + classTypeName.substring(1); } private String discoverPrefixFor(Class<?> classType, String suffix) { final String simpleName = classType.getSimpleName(); final String classNameWithoutVowels = VOWELS.matcher(simpleName.toLowerCase()).replaceAll(""); final String reducedClassName = classNameWithoutVowels.length() >= 3 ? classNameWithoutVowels : simpleName; String prefix = reducedClassName.substring(0, 3) + suffix; int i = 4; int numberedSuffix = 2; while (memory.forAlreadyUsedPrefixes().contains(prefix)) { if (i < reducedClassName.length()) { prefix = reducedClassName.substring(0, i) + suffix; i++; } else { prefix = reducedClassName.substring(0, 3) + suffix + numberedSuffix; numberedSuffix++; } } memory.forAlreadyUsedPrefixes().add(prefix); return prefix; } }