diff --git a/build.gradle b/build.gradle index 79c3f8d39c3..4dd89a12fa7 100644 --- a/build.gradle +++ b/build.gradle @@ -88,7 +88,7 @@ configure(allprojects) { project -> "http://aopalliance.sourceforge.net/doc/", "http://glassfish.java.net/nonav/docs/v3/api/", "http://docs.oracle.com/cd/E13222_01/wls/docs90/javadocs/", // commonj - "http://quartz-scheduler.org/api/2.1.5/", + "http://quartz-scheduler.org/api/2.1.7/", "http://www.eclipse.org/aspectj/doc/released/aspectj5rt-api/", "http://fasterxml.github.com/jackson-core/javadoc/2.2.0/", "http://jackson.codehaus.org/1.9.12/javadoc/", @@ -340,7 +340,7 @@ project("spring-oxm") { dependencies { compile(project(":spring-beans")) compile(project(":spring-core")) - optional(project(":spring-context")) // for Jaxb2Marshaller + testCompile(project(":spring-context")) optional("com.thoughtworks.xstream:xstream:1.4.4") optional("org.jibx:jibx-run:1.2.5") optional("org.apache.xmlbeans:xmlbeans:2.6.0") diff --git a/spring-oxm/src/main/java/org/springframework/oxm/jaxb/ClassPathJaxb2TypeScanner.java b/spring-oxm/src/main/java/org/springframework/oxm/jaxb/ClassPathJaxb2TypeScanner.java index c6f97d2493c..368655356b9 100644 --- a/spring-oxm/src/main/java/org/springframework/oxm/jaxb/ClassPathJaxb2TypeScanner.java +++ b/spring-oxm/src/main/java/org/springframework/oxm/jaxb/ClassPathJaxb2TypeScanner.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2012 the original author or authors. + * Copyright 2002-2013 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -25,10 +25,8 @@ import javax.xml.bind.annotation.XmlSeeAlso; import javax.xml.bind.annotation.XmlType; import org.springframework.core.io.Resource; -import org.springframework.core.io.ResourceLoader; import org.springframework.core.io.support.PathMatchingResourcePatternResolver; import org.springframework.core.io.support.ResourcePatternResolver; -import org.springframework.core.io.support.ResourcePatternUtils; import org.springframework.core.type.classreading.CachingMetadataReaderFactory; import org.springframework.core.type.classreading.MetadataReader; import org.springframework.core.type.classreading.MetadataReaderFactory; @@ -42,62 +40,54 @@ import org.springframework.util.ClassUtils; * Helper class for {@link Jaxb2Marshaller} that scans given packages for classes marked with JAXB2 annotations. * * @author Arjen Poutsma + * @author Juergen Hoeller * @author David Harrigan + * @since 3.1.1 * @see #scanPackages() */ class ClassPathJaxb2TypeScanner { private static final String RESOURCE_PATTERN = "/**/*.class"; - private final TypeFilter[] jaxb2TypeFilters = - new TypeFilter[]{new AnnotationTypeFilter(XmlRootElement.class, false), - new AnnotationTypeFilter(XmlType.class, false), new AnnotationTypeFilter(XmlSeeAlso.class, false), - new AnnotationTypeFilter(XmlEnum.class, false)}; + private static final TypeFilter[] JAXB2_TYPE_FILTERS = new TypeFilter[] { + new AnnotationTypeFilter(XmlRootElement.class, false), new AnnotationTypeFilter(XmlType.class, false), + new AnnotationTypeFilter(XmlSeeAlso.class, false), new AnnotationTypeFilter(XmlEnum.class, false)}; + + + private final ResourcePatternResolver resourcePatternResolver; private final String[] packagesToScan; - private ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver(); - private List> jaxb2Classes = new ArrayList>(); - - /** Constructs a new {@code ClassPathJaxb2TypeScanner} for the given packages. */ - ClassPathJaxb2TypeScanner(String[] packagesToScan) { + public ClassPathJaxb2TypeScanner(ClassLoader classLoader, String... packagesToScan) { Assert.notEmpty(packagesToScan, "'packagesToScan' must not be empty"); + this.resourcePatternResolver = new PathMatchingResourcePatternResolver(classLoader); this.packagesToScan = packagesToScan; } - void setResourceLoader(ResourceLoader resourceLoader) { - if (resourceLoader != null) { - this.resourcePatternResolver = ResourcePatternUtils.getResourcePatternResolver(resourceLoader); - } - } - - /** Returns the JAXB2 classes found in the specified packages. */ - Class[] getJaxb2Classes() { - return jaxb2Classes.toArray(new Class[jaxb2Classes.size()]); - } /** - * Scans the packages for classes marked with JAXB2 annotations. - * + * Scan the packages for classes marked with JAXB2 annotations. * @throws UncategorizedMappingException in case of errors */ - void scanPackages() throws UncategorizedMappingException { + public Class[] scanPackages() throws UncategorizedMappingException { try { - for (String packageToScan : packagesToScan) { + List> jaxb2Classes = new ArrayList>(); + for (String packageToScan : this.packagesToScan) { String pattern = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX + ClassUtils.convertClassNameToResourcePath(packageToScan) + RESOURCE_PATTERN; - Resource[] resources = resourcePatternResolver.getResources(pattern); - MetadataReaderFactory metadataReaderFactory = new CachingMetadataReaderFactory(resourcePatternResolver); + Resource[] resources = this.resourcePatternResolver.getResources(pattern); + MetadataReaderFactory metadataReaderFactory = new CachingMetadataReaderFactory(this.resourcePatternResolver); for (Resource resource : resources) { MetadataReader metadataReader = metadataReaderFactory.getMetadataReader(resource); if (isJaxb2Class(metadataReader, metadataReaderFactory)) { String className = metadataReader.getClassMetadata().getClassName(); - Class jaxb2AnnotatedClass = resourcePatternResolver.getClassLoader().loadClass(className); + Class jaxb2AnnotatedClass = this.resourcePatternResolver.getClassLoader().loadClass(className); jaxb2Classes.add(jaxb2AnnotatedClass); } } } + return jaxb2Classes.toArray(new Class[jaxb2Classes.size()]); } catch (IOException ex) { throw new UncategorizedMappingException("Failed to scan classpath for unlisted classes", ex); @@ -107,8 +97,8 @@ class ClassPathJaxb2TypeScanner { } } - private boolean isJaxb2Class(MetadataReader reader, MetadataReaderFactory factory) throws IOException { - for (TypeFilter filter : jaxb2TypeFilters) { + protected boolean isJaxb2Class(MetadataReader reader, MetadataReaderFactory factory) throws IOException { + for (TypeFilter filter : JAXB2_TYPE_FILTERS) { if (filter.match(reader, factory)) { return true; } @@ -116,5 +106,4 @@ class ClassPathJaxb2TypeScanner { return false; } - } diff --git a/spring-oxm/src/main/java/org/springframework/oxm/jaxb/Jaxb2Marshaller.java b/spring-oxm/src/main/java/org/springframework/oxm/jaxb/Jaxb2Marshaller.java index 8df021c7a6c..104e4f3d9bd 100644 --- a/spring-oxm/src/main/java/org/springframework/oxm/jaxb/Jaxb2Marshaller.java +++ b/spring-oxm/src/main/java/org/springframework/oxm/jaxb/Jaxb2Marshaller.java @@ -75,7 +75,6 @@ import org.xml.sax.helpers.XMLReaderFactory; import org.springframework.beans.factory.BeanClassLoaderAware; import org.springframework.beans.factory.InitializingBean; -import org.springframework.context.ResourceLoaderAware; import org.springframework.core.JdkVersion; import org.springframework.core.annotation.AnnotationUtils; import org.springframework.core.io.Resource; @@ -119,9 +118,8 @@ import org.springframework.util.xml.StaxUtils; * @see #setUnmarshallerListener(javax.xml.bind.Unmarshaller.Listener) * @see #setAdapters(XmlAdapter[]) */ -public class Jaxb2Marshaller - implements MimeMarshaller, MimeUnmarshaller, GenericMarshaller, GenericUnmarshaller, BeanClassLoaderAware, - ResourceLoaderAware, InitializingBean { +public class Jaxb2Marshaller implements MimeMarshaller, MimeUnmarshaller, GenericMarshaller, GenericUnmarshaller, + BeanClassLoaderAware, InitializingBean { private static final String CID = "cid:"; @@ -177,8 +175,8 @@ public class Jaxb2Marshaller /** - * Set multiple JAXB context paths. The given array of context paths is converted to a - * colon-delimited string, as supported by JAXB. + * Set multiple JAXB context paths. The given array of context paths gets + * converted to a colon-delimited string, as supported by JAXB. */ public void setContextPaths(String... contextPaths) { Assert.notEmpty(contextPaths, "'contextPaths' must not be empty"); @@ -187,8 +185,8 @@ public class Jaxb2Marshaller /** * Set a JAXB context path. - *

Setting this property, {@link #setClassesToBeBound "classesToBeBound"}, or - * {@link #setPackagesToScan "packagesToScan"} is required. + *

Setting either this property, {@link #setClassesToBeBound "classesToBeBound"} + * or {@link #setPackagesToScan "packagesToScan"} is required. */ public void setContextPath(String contextPath) { Assert.hasText(contextPath, "'contextPath' must not be null"); @@ -204,8 +202,8 @@ public class Jaxb2Marshaller /** * Set the list of Java classes to be recognized by a newly created JAXBContext. - *

Setting this property, {@link #setContextPath "contextPath"}, or - * {@link #setPackagesToScan "packagesToScan"} is required. + *

Setting either this property, {@link #setContextPath "contextPath"} + * or {@link #setPackagesToScan "packagesToScan"} is required. */ public void setClassesToBeBound(Class... classesToBeBound) { Assert.notEmpty(classesToBeBound, "'classesToBeBound' must not be empty"); @@ -220,10 +218,11 @@ public class Jaxb2Marshaller } /** - * Set the packages to search using Spring-based scanning for classes with JAXB2 annotations in the classpath. - *

Setting this property, {@link #setContextPath "contextPath"}, or - * {@link #setClassesToBeBound "classesToBeBound"} is required. This is analogous to Spring's component-scan feature - * ({@link org.springframework.context.annotation.ClassPathBeanDefinitionScanner}). + * Set the packages to search for classes with JAXB2 annotations in the classpath. + * This is using a Spring-bases search and therefore analogous to Spring's component-scan + * feature ({@link org.springframework.context.annotation.ClassPathBeanDefinitionScanner}). + *

Setting either this property, {@link #setContextPath "contextPath"} + * or {@link #setClassesToBeBound "classesToBeBound"} is required. */ public void setPackagesToScan(String[] packagesToScan) { this.packagesToScan = packagesToScan; @@ -390,12 +389,8 @@ public class Jaxb2Marshaller this.beanClassLoader = classLoader; } - public void setResourceLoader(ResourceLoader resourceLoader) { - this.resourceLoader = resourceLoader; - } - - public final void afterPropertiesSet() throws Exception { + public void afterPropertiesSet() throws Exception { boolean hasContextPath = StringUtils.hasLength(this.contextPath); boolean hasClassesToBeBound = !ObjectUtils.isEmpty(this.classesToBeBound); boolean hasPackagesToScan = !ObjectUtils.isEmpty(this.packagesToScan); @@ -487,10 +482,8 @@ public class Jaxb2Marshaller logger.info("Creating JAXBContext by scanning packages [" + StringUtils.arrayToCommaDelimitedString(this.packagesToScan) + "]"); } - ClassPathJaxb2TypeScanner scanner = new ClassPathJaxb2TypeScanner(this.packagesToScan); - scanner.setResourceLoader(this.resourceLoader); - scanner.scanPackages(); - Class[] jaxb2Classes = scanner.getJaxb2Classes(); + ClassPathJaxb2TypeScanner scanner = new ClassPathJaxb2TypeScanner(this.beanClassLoader, this.packagesToScan); + Class[] jaxb2Classes = scanner.scanPackages(); if (logger.isDebugEnabled()) { logger.debug("Found JAXB2 classes: [" + StringUtils.arrayToCommaDelimitedString(jaxb2Classes) + "]"); }