/******************************************************************************* * Copyright (c) 2011, 2015 Oracle and/or its affiliates. All rights reserved. * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0 * which accompanies this distribution. * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html * and the Eclipse Distribution License is available at * http://www.eclipse.org/org/documents/edl-v10.php. * * Contributors: * dclarke/tware - initial * tware ******************************************************************************/ package org.eclipse.persistence.jpa.rs.util.metadatasources; import java.util.Map; import javax.xml.bind.JAXBElement; import org.eclipse.persistence.descriptors.ClassDescriptor; import org.eclipse.persistence.dynamic.DynamicEntity; import org.eclipse.persistence.eis.mappings.EISCompositeCollectionMapping; import org.eclipse.persistence.eis.mappings.EISCompositeDirectCollectionMapping; import org.eclipse.persistence.internal.descriptors.VirtualAttributeAccessor; import org.eclipse.persistence.internal.jpa.weaving.RestAdapterClassWriter; import org.eclipse.persistence.internal.sessions.AbstractSession; import org.eclipse.persistence.jaxb.metadata.MetadataSource; import org.eclipse.persistence.jaxb.xmlmodel.JavaType; import org.eclipse.persistence.jaxb.xmlmodel.JavaType.JavaAttributes; import org.eclipse.persistence.jaxb.xmlmodel.ObjectFactory; import org.eclipse.persistence.jaxb.xmlmodel.XmlAccessMethods; import org.eclipse.persistence.jaxb.xmlmodel.XmlBindings; import org.eclipse.persistence.jaxb.xmlmodel.XmlBindings.JavaTypes; import org.eclipse.persistence.jaxb.xmlmodel.XmlElement; import org.eclipse.persistence.jaxb.xmlmodel.XmlJavaTypeAdapter; import org.eclipse.persistence.jaxb.xmlmodel.XmlVirtualAccessMethods; import org.eclipse.persistence.mappings.CollectionMapping; import org.eclipse.persistence.mappings.DatabaseMapping; import org.eclipse.persistence.mappings.ObjectReferenceMapping; /** * {@link MetadataSource} used in the creation of dynamic JAXB contexts for applications. * * @author dclarke * @since EclipseLink 2.4.0 */ public class DynamicXMLMetadataSource implements MetadataSource { private XmlBindings xmlBindings; public DynamicXMLMetadataSource(AbstractSession session, String packageName) { ObjectFactory objectFactory = new ObjectFactory(); xmlBindings = new XmlBindings(); xmlBindings.setPackageName(packageName); JavaTypes javaTypes = new JavaTypes(); xmlBindings.setJavaTypes(javaTypes); for (ClassDescriptor ormDescriptor : session.getProject().getOrderedDescriptors()) { String descriptorPackageName = ""; if (ormDescriptor.getJavaClassName().lastIndexOf('.') > 0) { descriptorPackageName = ormDescriptor.getJavaClassName().substring(0, ormDescriptor.getJavaClassName().lastIndexOf('.')); } if (descriptorPackageName.equals(packageName)) { javaTypes.getJavaType().add(createJAXBType(ormDescriptor, objectFactory)); } } } /** * Create a javaType to be used by JAXB to map a particular class. * For static classes, JAXB annotations, xml and defaults will be used to map the class. * For Dynamic classes we create properties for each JPA mapping on the class * thing we create is a * @param classDescriptor * @param objectFactory * @return */ private JavaType createJAXBType(ClassDescriptor classDescriptor, ObjectFactory objectFactory) { JavaType javaType = new JavaType(); String alias = classDescriptor.getAlias(); if (alias == null || alias.isEmpty()) { alias = classDescriptor.getJavaClass().getSimpleName(); } javaType.setName(alias); javaType.setJavaAttributes(new JavaAttributes()); boolean isDynamic = DynamicEntity.class.isAssignableFrom(classDescriptor.getJavaClass()); for (DatabaseMapping ormMapping : classDescriptor.getMappings()) { JAXBElement<XmlElement> element = createJAXBProperty(ormMapping, objectFactory, javaType, isDynamic); if (element != null) { javaType.getJavaAttributes().getJavaAttribute().add(element); } } // Embeddables don't need Rest adapters, return if the classDescriptor is an aggregate descriptor. if (classDescriptor.isAggregateDescriptor()) { return javaType; } // Set an adapter that is a subclass of ReferenceAdapter that can adapt the class to create a link for // the persistence_href field that has been weaved in. String name = RestAdapterClassWriter.constructClassNameForReferenceAdapter(classDescriptor.getJavaClassName()); XmlJavaTypeAdapter adapter = new XmlJavaTypeAdapter(); adapter.setValue(name); adapter.setValueType(classDescriptor.getJavaClassName()); adapter.setType(classDescriptor.getJavaClassName()); javaType.setXmlJavaTypeAdapter(adapter); return javaType; } /** * Create a JAXB property for a particular mapping. * This will only create JAXBProperties for mappings that are virtual - either because their * parent object is a dynamic class, or because the owning static class has virtual properties * @param mapping * @param objectFactory * @param owningType * @param isDynamic * @return */ private JAXBElement<XmlElement> createJAXBProperty(DatabaseMapping mapping, ObjectFactory objectFactory, JavaType owningType, boolean isDynamic) { if (!mapping.getAttributeAccessor().isVirtualAttributeAccessor() && !isDynamic) { return null; } XmlElement xmlElement = new XmlElement(); xmlElement.setJavaAttribute(mapping.getAttributeName()); if (mapping.isObjectReferenceMapping()) { xmlElement.setType(((ObjectReferenceMapping) mapping).getReferenceClassName()); } else if (mapping.isCollectionMapping()) { if (mapping.isEISMapping()) { // No way to find out the type of the collection from EIS mappings, currently, so just set the container policy here... // It will be fine for simple collections if (mapping instanceof EISCompositeDirectCollectionMapping) { xmlElement.setContainerType(((EISCompositeDirectCollectionMapping) mapping).getContainerPolicy().getContainerClassName()); } else if (mapping instanceof EISCompositeCollectionMapping) { xmlElement.setContainerType(((EISCompositeCollectionMapping) mapping).getContainerPolicy().getContainerClassName()); xmlElement.setType(((EISCompositeCollectionMapping) mapping).getReferenceClassName()); } } else { xmlElement.setType(((CollectionMapping) mapping).getReferenceClassName()); xmlElement.setContainerType(((CollectionMapping) mapping).getContainerPolicy().getContainerClassName()); } } else { xmlElement.setType(mapping.getAttributeClassification().getName()); } if (mapping.getAttributeAccessor().isVirtualAttributeAccessor()) { VirtualAttributeAccessor jpaAccessor = (VirtualAttributeAccessor) mapping.getAttributeAccessor(); if (owningType.getXmlVirtualAccessMethods() == null) { XmlVirtualAccessMethods virtualAccessMethods = new XmlVirtualAccessMethods(); virtualAccessMethods.setGetMethod(jpaAccessor.getGetMethodName()); virtualAccessMethods.setSetMethod(jpaAccessor.getSetMethodName()); owningType.setXmlVirtualAccessMethods(virtualAccessMethods); } else if (!owningType.getXmlVirtualAccessMethods().getGetMethod().equals(jpaAccessor.getGetMethodName())) { XmlAccessMethods accessMethods = new XmlAccessMethods(); accessMethods.setGetMethod(jpaAccessor.getGetMethodName()); accessMethods.setSetMethod(jpaAccessor.getSetMethodName()); xmlElement.setXmlAccessMethods(accessMethods); } } return objectFactory.createXmlElement(xmlElement); } public XmlBindings getXmlBindings(Map<String, ?> properties, ClassLoader classLoader) { return this.xmlBindings; } }