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.util.ClassUtils; 026 027/** 028 * Simple implementation of the {@link MetadataReaderFactory} interface, 029 * creating a new ASM {@link org.springframework.asm.ClassReader} for every request. 030 * 031 * @author Juergen Hoeller 032 * @since 2.5 033 */ 034public class SimpleMetadataReaderFactory implements MetadataReaderFactory { 035 036 private final ResourceLoader resourceLoader; 037 038 039 /** 040 * Create a new SimpleMetadataReaderFactory for the default class loader. 041 */ 042 public SimpleMetadataReaderFactory() { 043 this.resourceLoader = new DefaultResourceLoader(); 044 } 045 046 /** 047 * Create a new SimpleMetadataReaderFactory for the given resource loader. 048 * @param resourceLoader the Spring ResourceLoader to use 049 * (also determines the ClassLoader to use) 050 */ 051 public SimpleMetadataReaderFactory(ResourceLoader resourceLoader) { 052 this.resourceLoader = (resourceLoader != null ? resourceLoader : new DefaultResourceLoader()); 053 } 054 055 /** 056 * Create a new SimpleMetadataReaderFactory for the given class loader. 057 * @param classLoader the ClassLoader to use 058 */ 059 public SimpleMetadataReaderFactory(ClassLoader classLoader) { 060 this.resourceLoader = 061 (classLoader != null ? new DefaultResourceLoader(classLoader) : new DefaultResourceLoader()); 062 } 063 064 065 /** 066 * Return the ResourceLoader that this MetadataReaderFactory has been 067 * constructed with. 068 */ 069 public final ResourceLoader getResourceLoader() { 070 return this.resourceLoader; 071 } 072 073 074 @Override 075 public MetadataReader getMetadataReader(String className) throws IOException { 076 try { 077 String resourcePath = ResourceLoader.CLASSPATH_URL_PREFIX + 078 ClassUtils.convertClassNameToResourcePath(className) + ClassUtils.CLASS_FILE_SUFFIX; 079 Resource resource = this.resourceLoader.getResource(resourcePath); 080 return getMetadataReader(resource); 081 } 082 catch (FileNotFoundException ex) { 083 // Maybe an inner class name using the dot name syntax? Need to use the dollar syntax here... 084 // ClassUtils.forName has an equivalent check for resolution into Class references later on. 085 int lastDotIndex = className.lastIndexOf('.'); 086 if (lastDotIndex != -1) { 087 String innerClassName = 088 className.substring(0, lastDotIndex) + '$' + className.substring(lastDotIndex + 1); 089 String innerClassResourcePath = ResourceLoader.CLASSPATH_URL_PREFIX + 090 ClassUtils.convertClassNameToResourcePath(innerClassName) + ClassUtils.CLASS_FILE_SUFFIX; 091 Resource innerClassResource = this.resourceLoader.getResource(innerClassResourcePath); 092 if (innerClassResource.exists()) { 093 return getMetadataReader(innerClassResource); 094 } 095 } 096 throw ex; 097 } 098 } 099 100 @Override 101 public MetadataReader getMetadataReader(Resource resource) throws IOException { 102 return new SimpleMetadataReader(resource, this.resourceLoader.getClassLoader()); 103 } 104 105}