001/* 002 * Copyright 2015-2023 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 */ 016package com.mybatisflex.spring.boot; 017 018import org.apache.ibatis.io.VFS; 019import org.springframework.core.io.Resource; 020import org.springframework.core.io.support.PathMatchingResourcePatternResolver; 021import org.springframework.core.io.support.ResourcePatternResolver; 022 023import java.io.IOException; 024import java.io.UncheckedIOException; 025import java.net.URL; 026import java.net.URLDecoder; 027import java.nio.charset.Charset; 028import java.text.Normalizer; 029import java.util.List; 030import java.util.stream.Collectors; 031import java.util.stream.Stream; 032 033/** 034 * MyBatis 的 VFS 支持。 035 * 参考:https://github.com/mybatis/spring-boot-starter/blob/master/mybatis-spring-boot-autoconfigure/src/main/java/org/mybatis/spring/boot/autoconfigure/SpringBootVFS.java 036 * @author Hans Westerbeek 037 * @author Eddú Meléndez 038 * @author Kazuki Shimizu 039 * @author Michael 040 */ 041public class SpringBootVFS extends VFS { 042 043 private static Charset urlDecodingCharset; 044 045 static { 046 setUrlDecodingCharset(Charset.defaultCharset()); 047 } 048 049 private final ResourcePatternResolver resourceResolver; 050 051 public SpringBootVFS() { 052 this.resourceResolver = new PathMatchingResourcePatternResolver(getClass().getClassLoader()); 053 } 054 055 /** 056 * Set the charset for decoding an encoded URL string. 057 * <p> 058 * Default is system default charset. 059 * </p> 060 * 061 * @param charset the charset for decoding an encoded URL string 062 * @since 2.3.0 063 */ 064 public static void setUrlDecodingCharset(Charset charset) { 065 urlDecodingCharset = charset; 066 } 067 068 private static String preserveSubpackageName(final String baseUrlString, final Resource resource, 069 final String rootPath) { 070 try { 071 return rootPath + (rootPath.endsWith("/") ? "" : "/") + Normalizer 072 .normalize(URLDecoder.decode(resource.getURL().toString(), urlDecodingCharset.name()), Normalizer.Form.NFC) 073 .substring(baseUrlString.length()); 074 } catch (IOException e) { 075 throw new UncheckedIOException(e); 076 } 077 } 078 079 @Override 080 public boolean isValid() { 081 return true; 082 } 083 084 @Override 085 protected List<String> list(URL url, String path) throws IOException { 086 String urlString = URLDecoder.decode(url.toString(), urlDecodingCharset.name()); 087 String baseUrlString = urlString.endsWith("/") ? urlString : urlString.concat("/"); 088 Resource[] resources = resourceResolver.getResources(baseUrlString + "**/*.class"); 089 return Stream.of(resources).map(resource -> preserveSubpackageName(baseUrlString, resource, path)) 090 .collect(Collectors.toList()); 091 } 092 093}