From 5eb10a081765337974bf2906e4477483d2906c66 Mon Sep 17 00:00:00 2001 From: Oliver Gierke Date: Fri, 12 Jan 2018 10:31:44 +0100 Subject: [PATCH] DATACMNS-1206 - Polishing. Moved PropertyDescriptor lookup into dedicated subclass to group functionality around the type and MethodsMetadata instances. Extracted individual stream handling steps into dedicated methods for better understandability. Moved MethodsMetadataReader into classreading package for symmetry with Spring Framework's metadata arrangement. Removed manually declared getters in DefaultMethodsMetadataReader in favor of Lombok getters. Inlined MethodsMetadataReadingVisitor into DefaultMethodsMetadataReader as it's only used there. Original pull request: #263. --- .../DefaultProjectionInformation.java | 223 ++++++++++++------ .../data/type/MethodsMetadata.java | 1 + .../DefaultMethodsMetadataReader.java | 133 +++++++---- .../MethodsMetadataReader.java | 5 +- .../MethodsMetadataReaderFactory.java | 1 - .../MethodsMetadataReadingVisitor.java | 107 --------- ...DefaultMethodsMetadataReaderUnitTests.java | 1 - ...MethodsMetadataReaderFactoryUnitTests.java | 3 +- 8 files changed, 244 insertions(+), 230 deletions(-) rename src/main/java/org/springframework/data/type/{ => classreading}/MethodsMetadataReader.java (84%) delete mode 100644 src/main/java/org/springframework/data/type/classreading/MethodsMetadataReadingVisitor.java rename src/test/java/org/springframework/data/type/{ => classreading}/MethodsMetadataReaderFactoryUnitTests.java (94%) diff --git a/src/main/java/org/springframework/data/projection/DefaultProjectionInformation.java b/src/main/java/org/springframework/data/projection/DefaultProjectionInformation.java index 17fe50f30..294717dfc 100644 --- a/src/main/java/org/springframework/data/projection/DefaultProjectionInformation.java +++ b/src/main/java/org/springframework/data/projection/DefaultProjectionInformation.java @@ -15,10 +15,11 @@ */ package org.springframework.data.projection; +import lombok.extern.slf4j.Slf4j; + import java.beans.PropertyDescriptor; import java.io.IOException; import java.lang.reflect.Method; -import java.util.ArrayList; import java.util.Arrays; import java.util.Comparator; import java.util.List; @@ -29,11 +30,11 @@ import java.util.stream.IntStream; import java.util.stream.Stream; import org.springframework.beans.BeanUtils; -import org.springframework.core.type.ClassMetadata; import org.springframework.core.type.MethodMetadata; import org.springframework.data.type.MethodsMetadata; -import org.springframework.data.type.MethodsMetadataReader; +import org.springframework.data.type.classreading.MethodsMetadataReader; import org.springframework.data.type.classreading.MethodsMetadataReaderFactory; +import org.springframework.data.util.StreamUtils; import org.springframework.util.Assert; import org.springframework.util.ClassUtils; @@ -61,7 +62,7 @@ class DefaultProjectionInformation implements ProjectionInformation { Assert.notNull(type, "Projection type must not be null!"); this.projectionType = type; - this.properties = collectDescriptors(type); + this.properties = new PropertyDescriptorSource(type).getDescriptors(); } /* @@ -107,103 +108,171 @@ class DefaultProjectionInformation implements ProjectionInformation { } /** - * Collects {@link PropertyDescriptor}s for all properties exposed by the given type and all its super interfaces. + * Returns whether the given {@link PropertyDescriptor} has a getter that is a Java 8 default method. * - * @param type must not be {@literal null}. + * @param descriptor must not be {@literal null}. * @return */ - private static List collectDescriptors(Class type) { + private static boolean hasDefaultGetter(PropertyDescriptor descriptor) { - List result = new ArrayList<>(); + Method method = descriptor.getReadMethod(); - Optional metadata = getMetadata(type); - Stream stream = Arrays.stream(BeanUtils.getPropertyDescriptors(type))// - .filter(it -> !hasDefaultGetter(it)); + return method == null ? false : method.isDefault(); + } - Stream streamToUse = metadata.map(DefaultProjectionInformation::getMethodOrder) - .filter(it -> !it.isEmpty()) // - .map(it -> stream.filter(descriptor -> it.containsKey(descriptor.getReadMethod().getName())) - .sorted(Comparator.comparingInt(left -> it.get(left.getReadMethod().getName())))) // - .orElse(stream); + /** + * Internal helper to detect {@link PropertyDescriptor} instances for a given type. + * + * @author Mark Paluch + * @author Oliver Gierke + * @since 2.1 + * @soundtrack The Meters - Cissy Strut (Here Comes The Meter Man) + */ + @Slf4j + private static class PropertyDescriptorSource { - result.addAll(streamToUse.collect(Collectors.toList())); + private final Class type; + private final Optional metadata; - if (metadata.isPresent()) { + /** + * Creates a new {@link PropertyDescriptorSource} for the given type. + * + * @param type must not be {@literal null}. + */ + public PropertyDescriptorSource(Class type) { - Stream interfaceNames = metadata.map(ClassMetadata::getInterfaceNames) // - .map(Arrays::stream) // - .orElse(Stream.empty()); + Assert.notNull(type, "Type must not be null!"); - result.addAll(interfaceNames.map(it -> loadClass(it, type.getClassLoader())) // - .map(DefaultProjectionInformation::collectDescriptors) // - .flatMap(List::stream) // - .collect(Collectors.toList())); - } else { + this.type = type; + this.metadata = getMetadata(type); + } - for (Class interfaze : type.getInterfaces()) { - result.addAll(collectDescriptors(interfaze)); - } + /** + * Returns {@link PropertyDescriptor}s for all properties exposed by the given type and all its super interfaces. + * + * @return + */ + public List getDescriptors() { + return collectDescriptors().distinct().collect(StreamUtils.toUnmodifiableList()); } - return result.stream().distinct().collect(Collectors.toList()); - } + /** + * Recursively collects {@link PropertyDescriptor}s for all properties exposed by the given type and all its super + * interfaces. + * + * @return + */ + private Stream collectDescriptors() { + + Stream allButDefaultGetters = Arrays.stream(BeanUtils.getPropertyDescriptors(type)) // + .filter(it -> !hasDefaultGetter(it)); + + Stream ownDescriptors = metadata.map(it -> filterAndOrder(allButDefaultGetters, it)) + .orElse(allButDefaultGetters); - private static Class loadClass(String className, ClassLoader classLoader) { + Stream superTypeDescriptors = metadata.map(this::fromMetadata) // + .orElseGet(this::fromType) // + .flatMap(it -> new PropertyDescriptorSource(it).collectDescriptors()); - try { - return ClassUtils.forName(className, classLoader); - } catch (ClassNotFoundException e) { - throw new IllegalArgumentException(String.format("Cannot load class %s", className)); + return Stream.concat(ownDescriptors, superTypeDescriptors); } - } - /** - * Returns a {@link Map} containing method name to its positional index according to {@link MethodsMetadata}. - * - * @param metadata - * @return - */ - private static Map getMethodOrder(MethodsMetadata metadata) { + /** + * Returns a Stream of {@link PropertyDescriptor} ordered following the given {@link MethodsMetadata} only returning + * methods seen by the given {@link MethodsMetadata}. + * + * @param source must not be {@literal null}. + * @param metadata must not be {@literal null}. + * @return + */ + private static Stream filterAndOrder(Stream source, + MethodsMetadata metadata) { + + Map orderedMethods = getMethodOrder(metadata); + + if (orderedMethods.isEmpty()) { + return source; + } - List methods = metadata.getMethods() // - .stream() // - .map(MethodMetadata::getMethodName) // - .distinct() // - .collect(Collectors.toList()); + return source.filter(descriptor -> orderedMethods.containsKey(descriptor.getReadMethod().getName())) + .sorted(Comparator.comparingInt(left -> orderedMethods.get(left.getReadMethod().getName()))); + } - return IntStream.range(0, methods.size()) // - .boxed() // - .collect(Collectors.toMap(methods::get, i -> i)); - } + /** + * Returns a {@link Stream} of interfaces using the given {@link MethodsMetadata} as primary source for ordering. + * + * @param metadata must not be {@literal null}. + * @return + */ + private Stream> fromMetadata(MethodsMetadata metadata) { + return Arrays.stream(metadata.getInterfaceNames()).map(it -> findType(it, type.getInterfaces())); + } - /** - * Attempts to obtain {@link MethodsMetadata} from {@link Class}. Returns {@link Optional} containing - * {@link MethodsMetadata} if metadata was read successfully, {@link Optional#empty()} otherwise. - * - * @param type must not be {@literal null}. - * @return the optional {@link MethodsMetadata}. - */ - private static Optional getMetadata(Class type) { + /** + * Returns a Stream of interfaces using the given type as primary source for ordering. + * + * @return + */ + private Stream> fromType() { + return Arrays.stream(type.getInterfaces()); + } - try { + /** + * Attempts to obtain {@link MethodsMetadata} from {@link Class}. Returns {@link Optional} containing + * {@link MethodsMetadata} if metadata was read successfully, {@link Optional#empty()} otherwise. + * + * @param type must not be {@literal null}. + * @return the optional {@link MethodsMetadata}. + */ + private static Optional getMetadata(Class type) { - MethodsMetadataReaderFactory factory = new MethodsMetadataReaderFactory(type.getClassLoader()); - MethodsMetadataReader metadataReader = factory.getMetadataReader(ClassUtils.getQualifiedName(type)); - return Optional.of(metadataReader.getMethodsMetadata()); - } catch (IOException e) { - return Optional.empty(); + try { + + MethodsMetadataReaderFactory factory = new MethodsMetadataReaderFactory(type.getClassLoader()); + MethodsMetadataReader metadataReader = factory.getMetadataReader(ClassUtils.getQualifiedName(type)); + + return Optional.of(metadataReader.getMethodsMetadata()); + + } catch (IOException e) { + + LOG.info("Couldn't read class metadata for {}. Input property calculation might fail!", type); + + return Optional.empty(); + } } - } - /** - * Returns whether the given {@link PropertyDescriptor} has a getter that is a Java 8 default method. - * - * @param descriptor must not be {@literal null}. - * @return - */ - private static boolean hasDefaultGetter(PropertyDescriptor descriptor) { + /** + * Find the type with the given name in the given array of {@link Class}. + * + * @param name must not be {@literal null} or empty. + * @param types must not be {@literal null}. + * @return + */ + private static Class findType(String name, Class[] types) { + + return Arrays.stream(types) // + .filter(it -> name.equals(it.getName())) // + .findFirst() + .orElseThrow(() -> new IllegalStateException(String.format("Did not find type %s in %s!", name, types))); + } - Method method = descriptor.getReadMethod(); - return method == null ? false : method.isDefault(); + /** + * Returns a {@link Map} containing method name to its positional index according to {@link MethodsMetadata}. + * + * @param metadata + * @return + */ + private static Map getMethodOrder(MethodsMetadata metadata) { + + List methods = metadata.getMethods() // + .stream() // + .map(MethodMetadata::getMethodName) // + .distinct() // + .collect(Collectors.toList()); + + return IntStream.range(0, methods.size()) // + .boxed() // + .collect(Collectors.toMap(methods::get, i -> i)); + } } } diff --git a/src/main/java/org/springframework/data/type/MethodsMetadata.java b/src/main/java/org/springframework/data/type/MethodsMetadata.java index 74fc84988..d9bc3d601 100644 --- a/src/main/java/org/springframework/data/type/MethodsMetadata.java +++ b/src/main/java/org/springframework/data/type/MethodsMetadata.java @@ -19,6 +19,7 @@ import java.util.Set; import org.springframework.core.type.ClassMetadata; import org.springframework.core.type.MethodMetadata; +import org.springframework.data.type.classreading.MethodsMetadataReader; /** * Interface that defines abstract metadata of a specific class, in a form that does not require that class to be loaded diff --git a/src/main/java/org/springframework/data/type/classreading/DefaultMethodsMetadataReader.java b/src/main/java/org/springframework/data/type/classreading/DefaultMethodsMetadataReader.java index d201637a8..39e249693 100644 --- a/src/main/java/org/springframework/data/type/classreading/DefaultMethodsMetadataReader.java +++ b/src/main/java/org/springframework/data/type/classreading/DefaultMethodsMetadataReader.java @@ -15,18 +15,29 @@ */ package org.springframework.data.type.classreading; +import lombok.Getter; + import java.io.BufferedInputStream; import java.io.IOException; import java.io.InputStream; +import java.util.Collections; +import java.util.Set; import org.springframework.asm.ClassReader; +import org.springframework.asm.MethodVisitor; +import org.springframework.asm.Opcodes; +import org.springframework.asm.Type; import org.springframework.core.NestedIOException; import org.springframework.core.io.Resource; import org.springframework.core.type.AnnotationMetadata; import org.springframework.core.type.ClassMetadata; +import org.springframework.core.type.MethodMetadata; +import org.springframework.core.type.classreading.AnnotationMetadataReadingVisitor; +import org.springframework.core.type.classreading.MethodMetadataReadingVisitor; import org.springframework.data.type.MethodsMetadata; -import org.springframework.data.type.MethodsMetadataReader; +import org.springframework.data.util.StreamUtils; import org.springframework.lang.Nullable; +import org.springframework.util.Assert; /** * {@link MethodsMetadataReader} implementation based on an ASM {@link org.springframework.asm.ClassReader}. @@ -34,6 +45,7 @@ import org.springframework.lang.Nullable; * @author Mark Paluch * @since 2.1 */ +@Getter class DefaultMethodsMetadataReader implements MethodsMetadataReader { private final Resource resource; @@ -43,57 +55,96 @@ class DefaultMethodsMetadataReader implements MethodsMetadataReader { DefaultMethodsMetadataReader(Resource resource, @Nullable ClassLoader classLoader) throws IOException { + MethodsMetadataReadingVisitor visitor = new MethodsMetadataReadingVisitor(classLoader); + createClassReader(resource).accept(visitor, ClassReader.SKIP_DEBUG); + this.resource = resource; + this.classMetadata = visitor; + this.annotationMetadata = visitor; + this.methodsMetadata = visitor; + } - ClassReader classReader; + private static ClassReader createClassReader(Resource resource) throws IOException { + + try (InputStream is = new BufferedInputStream(resource.getInputStream())) { + + return new ClassReader(is); - try (InputStream is = new BufferedInputStream(getResource().getInputStream())) { - classReader = new ClassReader(is); } catch (IllegalArgumentException ex) { throw new NestedIOException("ASM ClassReader failed to parse class file - " - + "probably due to a new Java class file version that isn't supported yet: " + getResource(), ex); + + "probably due to a new Java class file version that isn't supported yet: " + resource, ex); } - - MethodsMetadataReadingVisitor visitor = new MethodsMetadataReadingVisitor(classLoader); - classReader.accept(visitor, ClassReader.SKIP_DEBUG); - - classMetadata = visitor; - annotationMetadata = visitor; - methodsMetadata = visitor; } - /* - * (non-Javadoc) - * @see org.springframework.core.type.classreading.MetadataReader#getResource() + /** + * ASM class visitor which looks for the class name and implemented types as well as for the methods defined in the + * class, exposing them through the {@link MethodsMetadata} interface. + * + * @author Mark Paluch + * @since 2.1 + * @see ClassMetadata + * @see MethodMetadata + * @see MethodMetadataReadingVisitor */ - @Override - public Resource getResource() { - return resource; - } + private static class MethodsMetadataReadingVisitor extends AnnotationMetadataReadingVisitor + implements MethodsMetadata { - /* - * (non-Javadoc) - * @see org.springframework.core.type.classreading.MetadataReader#getClassMetadata() - */ - @Override - public ClassMetadata getClassMetadata() { - return classMetadata; - } + /** + * Construct a new {@link MethodsMetadataReadingVisitor} given {@link ClassLoader}. + * + * @param classLoader may be {@literal null}. + */ + MethodsMetadataReadingVisitor(@Nullable ClassLoader classLoader) { + super(classLoader); + } - /* - * (non-Javadoc) - * @see org.springframework.core.type.classreading.MetadataReader#getAnnotationMetadata() - */ - @Override - public AnnotationMetadata getAnnotationMetadata() { - return annotationMetadata; - } + /* + * (non-Javadoc) + * @see org.springframework.core.type.classreading.AnnotationMetadataReadingVisitor#visitMethod(int, java.lang.String, java.lang.String, java.lang.String, java.lang.String[]) + */ + @Override + @SuppressWarnings("null") + public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) { - /* (non-Javadoc) - * @see org.springframework.data.util.ClassMetadataReader#getMethodsMetadata() - */ - @Override - public MethodsMetadata getMethodsMetadata() { - return methodsMetadata; + // Skip bridge methods - we're only interested in original user methods. + // On JDK 8, we'd otherwise run into double detection of the same method... + if ((access & Opcodes.ACC_BRIDGE) != 0) { + return super.visitMethod(access, name, desc, signature, exceptions); + } + + // Skip constructors + if (name.equals("")) { + return super.visitMethod(access, name, desc, signature, exceptions); + } + + MethodMetadataReadingVisitor visitor = new MethodMetadataReadingVisitor(name, access, getClassName(), + Type.getReturnType(desc).getClassName(), this.classLoader, this.methodMetadataSet); + + this.methodMetadataSet.add(visitor); + return visitor; + } + + /* + * (non-Javadoc) + * @see org.springframework.data.util.MethodsMetadata#getMethods() + */ + @Override + public Set getMethods() { + return Collections.unmodifiableSet(methodMetadataSet); + } + + /* + * (non-Javadoc) + * @see org.springframework.data.util.MethodsMetadata#getMethods(String) + */ + @Override + public Set getMethods(String name) { + + Assert.hasText(name, "Method name must not be null or empty"); + + return methodMetadataSet.stream() // + .filter(it -> it.getMethodName().equals(name)) // + .collect(StreamUtils.toUnmodifiableSet()); + } } } diff --git a/src/main/java/org/springframework/data/type/MethodsMetadataReader.java b/src/main/java/org/springframework/data/type/classreading/MethodsMetadataReader.java similarity index 84% rename from src/main/java/org/springframework/data/type/MethodsMetadataReader.java rename to src/main/java/org/springframework/data/type/classreading/MethodsMetadataReader.java index f21d64a99..f5797e473 100644 --- a/src/main/java/org/springframework/data/type/MethodsMetadataReader.java +++ b/src/main/java/org/springframework/data/type/classreading/MethodsMetadataReader.java @@ -13,9 +13,10 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.springframework.data.type; +package org.springframework.data.type.classreading; import org.springframework.core.type.classreading.MetadataReader; +import org.springframework.data.type.MethodsMetadata; /** * Extension to {@link MetadataReader} for accessing class metadata and method metadata as read by an ASM @@ -27,7 +28,7 @@ import org.springframework.core.type.classreading.MetadataReader; public interface MethodsMetadataReader extends MetadataReader { /** - * @return the metadata for methods in the class file. + * @return the {@link MethodsMetadata} for methods in the class file. */ MethodsMetadata getMethodsMetadata(); } diff --git a/src/main/java/org/springframework/data/type/classreading/MethodsMetadataReaderFactory.java b/src/main/java/org/springframework/data/type/classreading/MethodsMetadataReaderFactory.java index 6f4d249e0..d8a4f7921 100644 --- a/src/main/java/org/springframework/data/type/classreading/MethodsMetadataReaderFactory.java +++ b/src/main/java/org/springframework/data/type/classreading/MethodsMetadataReaderFactory.java @@ -21,7 +21,6 @@ import org.springframework.core.io.Resource; import org.springframework.core.io.ResourceLoader; import org.springframework.core.type.classreading.SimpleMetadataReaderFactory; import org.springframework.data.type.MethodsMetadata; -import org.springframework.data.type.MethodsMetadataReader; import org.springframework.lang.Nullable; /** diff --git a/src/main/java/org/springframework/data/type/classreading/MethodsMetadataReadingVisitor.java b/src/main/java/org/springframework/data/type/classreading/MethodsMetadataReadingVisitor.java deleted file mode 100644 index db3826c7c..000000000 --- a/src/main/java/org/springframework/data/type/classreading/MethodsMetadataReadingVisitor.java +++ /dev/null @@ -1,107 +0,0 @@ -/* - * Copyright 2018 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. - * 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 org.springframework.data.type.classreading; - -import java.util.Collections; -import java.util.LinkedHashSet; -import java.util.Set; - -import org.springframework.asm.MethodVisitor; -import org.springframework.asm.Opcodes; -import org.springframework.asm.Type; -import org.springframework.core.type.ClassMetadata; -import org.springframework.core.type.MethodMetadata; -import org.springframework.core.type.classreading.AnnotationMetadataReadingVisitor; -import org.springframework.core.type.classreading.MethodMetadataReadingVisitor; -import org.springframework.data.type.MethodsMetadata; -import org.springframework.lang.Nullable; -import org.springframework.util.Assert; - -/** - * ASM class visitor which looks for the class name and implemented types as well as for the methods defined in the - * class, exposing them through the {@link MethodsMetadata} interface. - * - * @author Mark Paluch - * @since 2.1 - * @see ClassMetadata - * @see MethodMetadata - * @see MethodMetadataReadingVisitor - */ -class MethodsMetadataReadingVisitor extends AnnotationMetadataReadingVisitor implements MethodsMetadata { - - /** - * Construct a new {@link MethodsMetadataReadingVisitor} given {@link ClassLoader}. - * - * @param classLoader may be {@literal null}. - */ - MethodsMetadataReadingVisitor(@Nullable ClassLoader classLoader) { - super(classLoader); - } - - /* - * (non-Javadoc) - * @see org.springframework.core.type.classreading.AnnotationMetadataReadingVisitor#visitMethod(int, java.lang.String, java.lang.String, java.lang.String, java.lang.String[]) - */ - @Override - public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) { - - // Skip bridge methods - we're only interested in original user methods. - // On JDK 8, we'd otherwise run into double detection of the same method... - if ((access & Opcodes.ACC_BRIDGE) != 0) { - return super.visitMethod(access, name, desc, signature, exceptions); - } - - // Skip constructors - if (name.equals("")) { - return super.visitMethod(access, name, desc, signature, exceptions); - } - - MethodMetadataReadingVisitor visitor = new MethodMetadataReadingVisitor(name, access, getClassName(), - Type.getReturnType(desc).getClassName(), this.classLoader, this.methodMetadataSet); - - this.methodMetadataSet.add(visitor); - return visitor; - } - - /* - * (non-Javadoc) - * @see org.springframework.data.util.MethodsMetadata#getMethods() - */ - @Override - public Set getMethods() { - return Collections.unmodifiableSet(methodMetadataSet); - } - - /* - * (non-Javadoc) - * @see org.springframework.data.util.MethodsMetadata#getMethods(String) - */ - @Override - public Set getMethods(String name) { - - Assert.hasText(name, "Method name must not be null or empty"); - - Set result = new LinkedHashSet<>(4); - - for (MethodMetadata metadata : methodMetadataSet) { - if (metadata.getMethodName().equals(name)) { - result.add(metadata); - } - } - - return Collections.unmodifiableSet(result); - } -} diff --git a/src/test/java/org/springframework/data/type/classreading/DefaultMethodsMetadataReaderUnitTests.java b/src/test/java/org/springframework/data/type/classreading/DefaultMethodsMetadataReaderUnitTests.java index 7d0937084..a81ebea6d 100644 --- a/src/test/java/org/springframework/data/type/classreading/DefaultMethodsMetadataReaderUnitTests.java +++ b/src/test/java/org/springframework/data/type/classreading/DefaultMethodsMetadataReaderUnitTests.java @@ -23,7 +23,6 @@ import java.util.Iterator; import org.junit.Test; import org.springframework.core.type.MethodMetadata; import org.springframework.data.type.MethodsMetadata; -import org.springframework.data.type.MethodsMetadataReader; /** * Unit tests for {@link DefaultMethodsMetadataReader}. diff --git a/src/test/java/org/springframework/data/type/MethodsMetadataReaderFactoryUnitTests.java b/src/test/java/org/springframework/data/type/classreading/MethodsMetadataReaderFactoryUnitTests.java similarity index 94% rename from src/test/java/org/springframework/data/type/MethodsMetadataReaderFactoryUnitTests.java rename to src/test/java/org/springframework/data/type/classreading/MethodsMetadataReaderFactoryUnitTests.java index 02d477294..dae9853c7 100644 --- a/src/test/java/org/springframework/data/type/MethodsMetadataReaderFactoryUnitTests.java +++ b/src/test/java/org/springframework/data/type/classreading/MethodsMetadataReaderFactoryUnitTests.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.springframework.data.type; +package org.springframework.data.type.classreading; import static org.assertj.core.api.Assertions.*; @@ -24,6 +24,7 @@ import java.net.URLClassLoader; import org.junit.Test; import org.springframework.core.io.DefaultResourceLoader; +import org.springframework.data.type.classreading.MethodsMetadataReader; import org.springframework.data.type.classreading.MethodsMetadataReaderFactory; /**