private Map<String, TypeIdentifier> analyzeClass(final String type, final Class<?> clazz) { if (clazz == null || isJDKType(type)) return Collections.emptyMap(); final XmlAccessType value = getXmlAccessType(clazz); // TODO analyze & test annotation inheritance ignoredFieldNames.clear(); final List<Field> relevantFields = Stream.of(clazz.getDeclaredFields()).filter(f -> isRelevant(f, value)).collect(Collectors.toList()); final List<Method> relevantGetters = Stream.of(clazz.getDeclaredMethods()).filter(m -> isRelevant(m, value)).collect(Collectors.toList()); final Map<String, TypeIdentifier> properties = new HashMap<>(); final Stream<Class<?>> allSuperTypes = Stream.concat(Stream.of(clazz.getInterfaces()), Stream.of(clazz.getSuperclass())); allSuperTypes.filter(Objects::nonNull).map(Type::getDescriptor).map(t -> analyzeClass(t, loadClassFromType(t))).forEach(properties::putAll); Stream.concat(relevantFields.stream().map(f -> mapField(f, type)), relevantGetters.stream().map(g -> mapGetter(g, type))) .filter(Objects::nonNull).forEach(p -> { properties.put(p.getLeft(), TypeIdentifier.ofType(p.getRight())); analyze(p.getRight()); }); return properties; }
private static boolean isRelevant(final Field field, final XmlAccessType accessType) { if (field.isSynthetic()) return false; if (hasIgnoreAnnotation(field) || isTypeIgnored(field.getType())) { ignoredFieldNames.add(field.getName()); return false; } if (isAnnotationPresent(field, XmlElement.class)) return true; final int modifiers = field.getModifiers(); if (accessType == XmlAccessType.FIELD) // always take, unless static or transient return !Modifier.isTransient(modifiers) && !Modifier.isStatic(modifiers) && !isAnnotationPresent(field, XmlTransient.class); else if (accessType == XmlAccessType.PUBLIC_MEMBER) // only for public, non-static return Modifier.isPublic(modifiers) && !Modifier.isStatic(modifiers) && !isAnnotationPresent(field, XmlTransient.class); return false; }
/** * Checks if the method is public and non-static and that the method is a Getter. * Does not allow methods with ignored names. * Does also not take methods annotated with {@link XmlTransient}. * * @param method The method * @return {@code true} if the method should be analyzed further */ private static boolean isRelevant(final Method method, final XmlAccessType accessType) { if (method.isSynthetic() || !isGetter(method)) return false; final boolean propertyIgnored = ignoredFieldNames.contains(extractPropertyName(method.getName())); if (propertyIgnored || hasIgnoreAnnotation(method) || isTypeIgnored(method.getReturnType())) { return false; } if (isAnnotationPresent(method, XmlElement.class)) return true; if (accessType == XmlAccessType.PROPERTY) return !isAnnotationPresent(method, XmlTransient.class); else if (accessType == XmlAccessType.PUBLIC_MEMBER) return Modifier.isPublic(method.getModifiers()) && !isAnnotationPresent(method, XmlTransient.class); return false; }
/** * Checks if the field is accepted as a JAXB property. */ static boolean isFieldAccepted(Field field, XmlAccessType accessType) { // We only accept non static fields which are not marked @XmlTransient if (Modifier.isStatic(field.getModifiers()) || field.isAnnotationPresent(XmlTransient.class)) { return false; } if (accessType == XmlAccessType.PUBLIC_MEMBER && !Modifier.isPublic(field.getModifiers())) { return false; } if (field.getAnnotation(XmlJavaTypeAdapter.class) != null) { return false; } if (accessType == XmlAccessType.NONE || accessType == XmlAccessType.PROPERTY) { return checkJaxbAnnotation(field.getAnnotations()); } else { return true; } }
/** * Computes the {@link XmlAccessType} on this class by looking at {@link XmlAccessorType} * annotations. */ private XmlAccessType getAccessType() { XmlAccessorType xat = getClassOrPackageAnnotation(XmlAccessorType.class); if(xat!=null) return xat.value(); else return XmlAccessType.PUBLIC_MEMBER; }
private void writeXmlElementDeclaration(JDefinedClass cls, String elementName, String namespaceUri) { if (cls == null) return; JAnnotationUse xmlRootElementAnn = cls.annotate(XmlRootElement.class); xmlRootElementAnn.param("name", elementName); if (namespaceUri.length() > 0) { xmlRootElementAnn.param("namespace", namespaceUri); } JAnnotationUse xmlAccessorTypeAnn = cls.annotate(cm.ref(XmlAccessorType.class)); xmlAccessorTypeAnn.param("value", XmlAccessType.FIELD); }
private void renderClassLevelAnnotations(JDefinedClass classModel, List<FieldModel> fields) throws Exception { JFieldRef constantsClass = classModel.staticRef(Util.CONSTANTS_CLASS_NAME); JFieldRef elementsClass = classModel.staticRef(Util.ELEMENTS_CLASS_NAME); JClass coreConstants = codeModel.ref(CoreConstants.class); JFieldRef commonElementsRef = coreConstants.staticRef("CommonElements"); // XmlRootElement JAnnotationUse rootElementAnnotation = classModel.annotate(XmlRootElement.class); rootElementAnnotation.param("name", constantsClass.ref(Util.ROOT_ELEMENT_NAME_FIELD)); // XmlAccessorType JAnnotationUse xmlAccessorTypeAnnotation = classModel.annotate(XmlAccessorType.class); xmlAccessorTypeAnnotation.param("value", XmlAccessType.NONE); // XmlType JAnnotationUse xmlTypeAnnotation = classModel.annotate(XmlType.class); xmlTypeAnnotation.param("name", constantsClass.ref(Util.TYPE_NAME_FIELD)); JAnnotationArrayMember propOrderMember = xmlTypeAnnotation.paramArray("propOrder"); for (FieldModel field : fields) { if (Util.isCommonElement(field.fieldName)) { propOrderMember.param(commonElementsRef.ref(Util.toConstantsVariable(field.fieldName))); } else { propOrderMember.param(elementsClass.ref(Util.toConstantsVariable(field.fieldName))); } } propOrderMember.param(commonElementsRef.ref("FUTURE_ELEMENTS")); }
private XmlAccessType getXmlAccessType(final Class<?> clazz) { Class<?> current = clazz; while (current != null) { if (isAnnotationPresent(current, XmlAccessorType.class)) return getAnnotation(current, XmlAccessorType.class).value(); current = current.getSuperclass(); } return XmlAccessType.PUBLIC_MEMBER; }
private void findFieldProperties(C c, XmlAccessType at) { // always find properties from the super class first C sc = nav().getSuperClass(c); if (shouldRecurseSuperClass(sc)) { findFieldProperties(sc,at); } for( F f : nav().getDeclaredFields(c) ) { Annotation[] annotations = reader().getAllFieldAnnotations(f,this); boolean isDummy = reader().hasFieldAnnotation(OverrideAnnotationOf.class, f); if( nav().isTransient(f) ) { // it's an error for transient field to have any binding annotation if(hasJAXBAnnotation(annotations)) builder.reportError(new IllegalAnnotationException( Messages.TRANSIENT_FIELD_NOT_BINDABLE.format(nav().getFieldName(f)), getSomeJAXBAnnotation(annotations))); } else if( nav().isStaticField(f) ) { // static fields are bound only when there's explicit annotation. if(hasJAXBAnnotation(annotations)) addProperty(createFieldSeed(f),annotations, false); } else { if(at==XmlAccessType.FIELD ||(at==XmlAccessType.PUBLIC_MEMBER && nav().isPublicField(f)) || hasJAXBAnnotation(annotations)) { if (isDummy) { ClassInfo<T, C> top = getBaseClass(); while ((top != null) && (top.getProperty("content") == null)) { top = top.getBaseClass(); } DummyPropertyInfo prop = (DummyPropertyInfo) top.getProperty("content"); PropertySeed seed = createFieldSeed(f); ((DummyPropertyInfo)prop).addType(createReferenceProperty(seed)); } else { addProperty(createFieldSeed(f), annotations, false); } } checkFieldXmlLocation(f); } } }
public static void marshallException(Marshaller marshaller, Exception elValue, MessagePartInfo part, Object source) { XMLStreamWriter writer = getStreamWriter(source); QName qn = part.getElementQName(); try { writer.writeStartElement("ns1", qn.getLocalPart(), qn.getNamespaceURI()); Class<?> cls = part.getTypeClass(); XmlAccessorType accessorType = cls.getAnnotation(XmlAccessorType.class); if (accessorType == null && cls.getPackage() != null) { accessorType = cls.getPackage().getAnnotation(XmlAccessorType.class); } XmlAccessType accessType = accessorType != null ? accessorType.value() : XmlAccessType.PUBLIC_MEMBER; String namespace = part.getElementQName().getNamespaceURI(); SchemaInfo sch = part.getMessageInfo().getOperation().getInterface() .getService().getSchema(namespace); if (sch != null) { if (!sch.isElementFormQualified()) { namespace = null; } } else { LOG.warning("Schema associated with " + namespace + " is null"); } for (Field f : cls.getDeclaredFields()) { if (JAXBContextInitializer.isFieldAccepted(f, accessType)) { QName fname = new QName(namespace, f.getName()); f.setAccessible(true); if (JAXBSchemaInitializer.isArray(f.getGenericType())) { writeArrayObject(marshaller, writer, fname, f.get(elValue)); } else { writeObject(marshaller, writer, new JAXBElement(fname, String.class, f.get(elValue))); } } } for (Method m : cls.getMethods()) { if (JAXBContextInitializer.isMethodAccepted(m, accessType)) { int idx = m.getName().startsWith("get") ? 3 : 2; String name = m.getName().substring(idx); name = Character.toLowerCase(name.charAt(0)) + name.substring(1); QName mname = new QName(namespace, name); if (JAXBSchemaInitializer.isArray(m.getGenericReturnType())) { writeArrayObject(marshaller, writer, mname, m.invoke(elValue)); } else { writeObject(marshaller, writer, new JAXBElement(mname, String.class, m.invoke(elValue))); } } } writer.writeEndElement(); writer.flush(); } catch (Exception e) { throw new Fault(new Message("MARSHAL_ERROR", LOG, e.getMessage()), e); } }
@SuppressWarnings("unchecked") private void findFieldProperties(C c, XmlAccessType at) { // always find properties from the super class first C sc = nav().getSuperClass(c); if (shouldRecurseSuperClass(sc)) { findFieldProperties(sc,at); } for( F f : nav().getDeclaredFields(c) ) { Annotation[] annotations = reader().getAllFieldAnnotations(f,this); boolean isDummy = reader().hasFieldAnnotation(OverrideAnnotationOf.class, f); if( nav().isTransient(f) ) { // it's an error for transient field to have any binding annotation if(hasJAXBAnnotation(annotations)) builder.reportError(new IllegalAnnotationException( Messages.TRANSIENT_FIELD_NOT_BINDABLE.format(nav().getFieldName(f)), getSomeJAXBAnnotation(annotations))); } else if( nav().isStaticField(f) ) { // static fields are bound only when there's explicit annotation. if(hasJAXBAnnotation(annotations)) addProperty(createFieldSeed(f),annotations, false); } else { if(at==XmlAccessType.FIELD ||(at==XmlAccessType.PUBLIC_MEMBER && nav().isPublicField(f)) || hasJAXBAnnotation(annotations)) { if (isDummy) { ClassInfo<T, C> top = getBaseClass(); while ((top != null) && (top.getProperty("content") == null)) { top = top.getBaseClass(); } DummyPropertyInfo prop = (DummyPropertyInfo) top.getProperty("content"); PropertySeed seed = createFieldSeed(f); ((DummyPropertyInfo<T,C,F,M>)prop).addType(createReferenceProperty(seed)); } else { addProperty(createFieldSeed(f), annotations, false); } } checkFieldXmlLocation(f); } } }
@Test public void shouldHaveClassAnnotations() { Class<DateModuleResultXml> xmlClass = DateModuleResultXml.class; assertEquals("dateModuleResult", xmlClass.getAnnotation(XmlRootElement.class).name()); assertEquals(XmlAccessType.FIELD, xmlClass.getAnnotation(XmlAccessorType.class).value()); }
@Test public void shouldHaveClassAnnotations() { Class<DateMetricResultXml> xmlClass = DateMetricResultXml.class; assertEquals("dateMetricResult", xmlClass.getAnnotation(XmlRootElement.class).name()); assertEquals(XmlAccessType.FIELD, xmlClass.getAnnotation(XmlAccessorType.class).value()); }
@Test public void shouldHaveClassAnnotations() { Class<ProcessTimeXml> xmlClass = ProcessTimeXml.class; assertEquals("stateTime", xmlClass.getAnnotation(XmlRootElement.class).name()); assertEquals(XmlAccessType.FIELD, xmlClass.getAnnotation(XmlAccessorType.class).value()); }
@Test public void shouldHaveFieldXmlAccess() throws ClassNotFoundException { XmlAccessorType accessorType = dtoClass().getAnnotation(XmlAccessorType.class); assertNotNull(accessorType); assertEquals(XmlAccessType.FIELD, accessorType.value()); }
/** * Checks if the method is accepted as a JAXB property getter. */ static boolean isMethodAccepted(Method method, XmlAccessType accessType) { // We only accept non static property getters which are not marked @XmlTransient if (Modifier.isStatic(method.getModifiers()) || method.isAnnotationPresent(XmlTransient.class) || !Modifier.isPublic(method.getModifiers())) { return false; } // must not have parameters and return type must not be void if (method.getReturnType() == Void.class || method.getParameterTypes().length != 0 || method.getDeclaringClass().equals(Throwable.class)) { return false; } boolean isPropGetter = method.getName().startsWith("get") || method.getName().startsWith("is"); if (!isPropGetter || method.getAnnotation(XmlJavaTypeAdapter.class) != null) { return false; } int beginIndex = 3; if (method.getName().startsWith("is")) { beginIndex = 2; } try { method.getDeclaringClass().getMethod("set" + method.getName().substring(beginIndex), new Class[] {method.getReturnType()}); } catch (Exception e) { //getter, but no setter return false; } if (accessType == XmlAccessType.NONE || accessType == XmlAccessType.FIELD) { return checkJaxbAnnotation(method.getAnnotations()); } else { return true; } }