001/* 002 * Copyright 2002-2018 the original author or authors. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * https://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017package org.springframework.core.type.classreading; 018 019import java.io.FileNotFoundException; 020import java.io.IOException; 021 022import org.springframework.core.io.DefaultResourceLoader; 023import org.springframework.core.io.Resource; 024import org.springframework.core.io.ResourceLoader; 025import org.springframework.lang.Nullable; 026import org.springframework.util.ClassUtils; 027 028/** 029 * Simple implementation of the {@link MetadataReaderFactory} interface, 030 * creating a new ASM {@link org.springframework.asm.ClassReader} for every request. 031 * 032 * @author Juergen Hoeller 033 * @since 2.5 034 */ 035public class SimpleMetadataReaderFactory implements MetadataReaderFactory { 036 037 private final ResourceLoader resourceLoader; 038 039 040 /** 041 * Create a new SimpleMetadataReaderFactory for the default class loader. 042 */ 043 public SimpleMetadataReaderFactory() { 044 this.resourceLoader = new DefaultResourceLoader(); 045 } 046 047 /** 048 * Create a new SimpleMetadataReaderFactory for the given resource loader. 049 * @param resourceLoader the Spring ResourceLoader to use 050 * (also determines the ClassLoader to use) 051 */ 052 public SimpleMetadataReaderFactory(@Nullable ResourceLoader resourceLoader) { 053 this.resourceLoader = (resourceLoader != null ? resourceLoader : new DefaultResourceLoader()); 054 } 055 056 /** 057 * Create a new SimpleMetadataReaderFactory for the given class loader. 058 * @param classLoader the ClassLoader to use 059 */ 060 public SimpleMetadataReaderFactory(@Nullable ClassLoader classLoader) { 061 this.resourceLoader = 062 (classLoader != null ? new DefaultResourceLoader(classLoader) : new DefaultResourceLoader()); 063 } 064 065 066 /** 067 * Return the ResourceLoader that this MetadataReaderFactory has been 068 * constructed with. 069 */ 070 public final ResourceLoader getResourceLoader() { 071 return this.resourceLoader; 072 } 073 074 075 @Override 076 public MetadataReader getMetadataReader(String className) throws IOException { 077 try { 078 String resourcePath = ResourceLoader.CLASSPATH_URL_PREFIX + 079 ClassUtils.convertClassNameToResourcePath(className) + ClassUtils.CLASS_FILE_SUFFIX; 080 Resource resource = this.resourceLoader.getResource(resourcePath); 081 return getMetadataReader(resource); 082 } 083 catch (FileNotFoundException ex) { 084 // Maybe an inner class name using the dot name syntax? Need to use the dollar syntax here... 085 // ClassUtils.forName has an equivalent check for resolution into Class references later on. 086 int lastDotIndex = className.lastIndexOf('.'); 087 if (lastDotIndex != -1) { 088 String innerClassName = 089 className.substring(0, lastDotIndex) + '$' + className.substring(lastDotIndex + 1); 090 String innerClassResourcePath = ResourceLoader.CLASSPATH_URL_PREFIX + 091 ClassUtils.convertClassNameToResourcePath(innerClassName) + ClassUtils.CLASS_FILE_SUFFIX; 092 Resource innerClassResource = this.resourceLoader.getResource(innerClassResourcePath); 093 if (innerClassResource.exists()) { 094 return getMetadataReader(innerClassResource); 095 } 096 } 097 throw ex; 098 } 099 } 100 101 @Override 102 public MetadataReader getMetadataReader(Resource resource) throws IOException { 103 return new SimpleMetadataReader(resource, this.resourceLoader.getClassLoader()); 104 } 105 106}