| /* |
| * Copyright (c) 2011, 2021 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 v. 2.0 which is available at |
| * http://www.eclipse.org/legal/epl-2.0, |
| * or the Eclipse Distribution License v. 1.0 which is available at |
| * http://www.eclipse.org/org/documents/edl-v10.php. |
| * |
| * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause |
| */ |
| |
| // Contributors: |
| // Rick Barkhouse - 2.1 - Initial implementation |
| package org.eclipse.persistence.jaxb.javamodel.xjc; |
| |
| import java.lang.annotation.Annotation; |
| import java.lang.reflect.Method; |
| import java.util.ArrayList; |
| import java.util.Collection; |
| import java.util.HashMap; |
| import java.util.List; |
| import java.util.Map; |
| |
| import jakarta.xml.bind.annotation.XmlEnum; |
| |
| import org.eclipse.persistence.dynamic.DynamicClassLoader; |
| import org.eclipse.persistence.internal.oxm.XMLConversionManager; |
| import org.eclipse.persistence.jaxb.javamodel.AnnotationProxy; |
| import org.eclipse.persistence.jaxb.javamodel.JavaAnnotation; |
| |
| import com.sun.codemodel.JAnnotationArrayMember; |
| import com.sun.codemodel.JAnnotationClassValue; |
| import com.sun.codemodel.JAnnotationStringValue; |
| import com.sun.codemodel.JAnnotationUse; |
| import com.sun.codemodel.JAnnotationValue; |
| import com.sun.codemodel.JClass; |
| import com.sun.codemodel.JType; |
| |
| /** |
| * INTERNAL: |
| * <p> |
| * <b>Purpose:</b> <code>JavaAnnotation</code> implementation wrapping XJC's <code>JAnnotationUse</code>. Used when |
| * bootstrapping a <code>DynamicJAXBContext</code> from an XML Schema. |
| * </p> |
| * |
| * <p> |
| * <b>Responsibilities:</b> |
| * </p> |
| * <ul> |
| * <li>Provide <code>Annotation</code> information from the underlying <code>JAnnotationUse</code>.</li> |
| * </ul> |
| * |
| * @since EclipseLink 2.1 |
| * |
| * @see org.eclipse.persistence.jaxb.javamodel.JavaAnnotation |
| */ |
| public class XJCJavaAnnotationImpl implements JavaAnnotation { |
| |
| private JAnnotationUse xjcAnnotation; |
| private DynamicClassLoader dynamicClassLoader; |
| |
| /** |
| * Construct a new instance of <code>XJCJavaAnnotationImpl</code>. |
| * |
| * @param annotation - the XJC <code>JAnnotationUse</code> to be wrapped. |
| * @param loader - the <code>ClassLoader</code> used to bootstrap the <code>DynamicJAXBContext</code>. |
| */ |
| public XJCJavaAnnotationImpl(JAnnotationUse annotation, DynamicClassLoader loader) { |
| this.xjcAnnotation = annotation; |
| this.dynamicClassLoader = loader; |
| } |
| |
| /** |
| * Return a Java <code>Annotation</code> representation of this <code>JavaAnnotation</code>. |
| * |
| * @return a Java <code>Annotation</code> representation of this <code>JavaAnnotation</code>. |
| */ |
| @SuppressWarnings("unchecked") |
| public Annotation getJavaAnnotation() { |
| try { |
| Map<String, Object> components = new HashMap<>(); |
| |
| // First, get all the default values for this annotation class. |
| Class<Annotation> annotationClass = (Class<Annotation>) getJavaAnnotationClass(); |
| Method[] methods = annotationClass.getDeclaredMethods(); |
| for (int i = 0; i < methods.length; i++) { |
| components.put(methods[i].getName(), methods[i].getDefaultValue()); |
| } |
| |
| // Get the property values for this annotation instance. |
| Map<String, JAnnotationValue> memberValues = xjcAnnotation.getAnnotationMembers(); |
| if (memberValues == null) { |
| // Return an annotation with just the defaults set. |
| return AnnotationProxy.getProxy(components, annotationClass, dynamicClassLoader, XMLConversionManager.getDefaultManager()); |
| } |
| |
| boolean isXmlEnum = annotationClass.equals(XmlEnum.class); |
| // Now overwrite the default values with anything we find in the XJC annotation instance. |
| for (String key : memberValues.keySet()) { |
| JAnnotationValue xjcValue = memberValues.get(key); |
| if (xjcValue instanceof JAnnotationArrayMember) { |
| Collection<JAnnotationValue> values = ((JAnnotationArrayMember) xjcValue).annotations2(); |
| List<Object> valuesArray = new ArrayList<>(values.size()); |
| for (JAnnotationValue val : values) { |
| if (val instanceof JAnnotationUse) { |
| JAnnotationUse xjcAnno = (JAnnotationUse) val; |
| XJCJavaAnnotationImpl anno = new XJCJavaAnnotationImpl(xjcAnno, dynamicClassLoader); |
| valuesArray.add(anno.getJavaAnnotation()); |
| } else if (val instanceof JAnnotationStringValue) { |
| JAnnotationStringValue value = (JAnnotationStringValue) val; |
| valuesArray.add(value.toString()); |
| } else if (val instanceof JAnnotationClassValue) { |
| JAnnotationClassValue cval = (JAnnotationClassValue) val; |
| valuesArray.add(getValueFromClsValue(cval, isXmlEnum)); |
| } else { |
| throw new RuntimeException("got " + val.getClass().getName()); |
| } |
| } |
| components.put(key, valuesArray.toArray(new Object[valuesArray.size()])); |
| } else if (xjcValue instanceof JAnnotationStringValue) { |
| JAnnotationStringValue value = (JAnnotationStringValue) xjcValue; |
| components.put(key, value.toString()); |
| } else if (xjcValue instanceof JAnnotationClassValue) { |
| JAnnotationClassValue cval = (JAnnotationClassValue) xjcValue; |
| components.put(key, getValueFromClsValue(cval, isXmlEnum)); |
| } else { |
| throw new RuntimeException("got " + xjcValue.getClass().getName()); |
| } |
| } |
| |
| return AnnotationProxy.getProxy(components, annotationClass, dynamicClassLoader, XMLConversionManager.getDefaultManager()); |
| } catch (Exception e) { |
| return null; |
| } |
| } |
| |
| /** |
| * Return the Java <code>Class</code> of the <code>Annotation</code> represented by this <code>JavaAnnotation</code>. |
| * |
| * @return the Java <code>Class</code> of this <code>JavaAnnotation's</code> <code>Annotation</code>. |
| */ |
| public Class<?> getJavaAnnotationClass() { |
| try { |
| return Class.forName(getName()); |
| } catch (ClassNotFoundException e) { |
| return null; |
| } |
| } |
| |
| /** |
| * Not supported. |
| */ |
| @Override |
| public Map<Object, Object> getComponents() { |
| throw new UnsupportedOperationException("getComponents"); |
| } |
| |
| @Override |
| @SuppressWarnings("unchecked") |
| public String getName() { |
| return xjcAnnotation.getAnnotationClass().binaryName(); |
| } |
| |
| private Object getValueFromClsValue(JAnnotationClassValue value, boolean isXmlEnum) { |
| JClass cls = value.type(); |
| for (JType param : cls.getTypeParameters()) { |
| String name = param.boxify().fullName(); |
| getTempClass(name, isXmlEnum); |
| } |
| Class<?> tempDynClass = getTempClass(cls.fullName(), isXmlEnum); |
| if (tempDynClass.isEnum() && !isXmlEnum) { |
| return Enum.valueOf(tempDynClass.asSubclass(Enum.class), value.value()); |
| } |
| return tempDynClass; |
| } |
| |
| private Class<?> getTempClass(String name, boolean isXmlEnum) { |
| Class<?> tempDynClass; |
| try { |
| // Attempt to look up the class normally |
| tempDynClass = Class.forName(name); |
| } catch (ClassNotFoundException e) { |
| if (isXmlEnum) { |
| tempDynClass = String.class; |
| } else { |
| tempDynClass = dynamicClassLoader.createDynamicClass(name); |
| } |
| } |
| return tempDynClass; |
| } |
| } |