Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ Apollo Java 2.6.0

------------------

*
* [Fix Apollo client local cache fallback for Spring Boot 3 executable JARs](https://github.com/apolloconfig/apollo-java/pull/136)

------------------
All issues and pull requests are [here](https://github.com/apolloconfig/apollo-java/milestone/6?closed=1)
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,10 @@
package com.ctrip.framework.apollo.core.utils;

import com.google.common.base.Strings;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.net.URL;
import java.net.URLDecoder;
import java.nio.file.Paths;

/**
* @author Jason Song(song_s@ctrip.com)
Expand All @@ -39,20 +37,11 @@ public class ClassLoaderUtil {
loader = ClassLoader.getSystemClassLoader();
}

String defaultClassPath = System.getProperty("user.dir");
try {
URL url = loader.getResource("");
// get class path
if (url != null) {
classPath = url.getPath();
classPath = URLDecoder.decode(classPath, "utf-8");
}

// 如果是jar包内的,则返回当前路径
if (Strings.isNullOrEmpty(classPath) || classPath.contains(".jar!")) {
classPath = System.getProperty("user.dir");
}
classPath = resolveClassPath(loader, defaultClassPath);
} catch (Throwable ex) {
classPath = System.getProperty("user.dir");
classPath = defaultClassPath;
logger.warn("Failed to locate class path, fallback to user.dir: {}", classPath, ex);
}
}
Expand All @@ -65,6 +54,19 @@ public static String getClassPath() {
return classPath;
}

static String resolveClassPath(ClassLoader classLoader, String defaultClassPath) throws Exception {
URL url = classLoader.getResource("");
if (url == null || !"file".equalsIgnoreCase(url.getProtocol())) {
return defaultClassPath;
}

String resolvedClassPath = Paths.get(url.toURI()).toString();
if (Strings.isNullOrEmpty(resolvedClassPath)) {
return defaultClassPath;
}
Comment on lines +57 to +66
Copy link

Copilot AI Apr 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

resolveClassPath now derives the classpath via Paths.get(url.toURI()).toString(), which changes the returned format on Windows (it will no longer include the leading / that URL#getPath() produced). There is existing code in the repo that compensates for the old behavior (e.g. apollo-client/src/test/java/com/ctrip/framework/apollo/BaseIntegrationTest.java strips the leading /), which will become incorrect with this change and can break Windows builds/tests. Consider either preserving the previous Windows formatting (e.g. keep using the decoded url.getPath() for file: URLs) or updating the affected call sites/tests to stop assuming a leading / from getClassPath().

Copilot uses AI. Check for mistakes.
return resolvedClassPath;
}

public static boolean isClassPresent(String className) {
try {
Class.forName(className);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,42 @@

import static org.junit.Assert.*;

import java.net.URL;
import java.net.URLConnection;
import java.net.URLStreamHandler;
import java.nio.file.Files;
import java.nio.file.Path;
import org.junit.Test;

public class ClassLoaderUtilTest {
private static boolean shouldFailInInitialization = false;

@Test
public void testGetClassLoader() {
assertNotNull(ClassLoaderUtil.getLoader());
}

@Test
public void testResolveClassPathWithFileUrl() throws Exception {
Path tempDir = Files.createTempDirectory("apollo class path");
try {
ClassLoader classLoader = classLoaderReturning(tempDir.toUri().toURL());

assertEquals(tempDir.toString(), ClassLoaderUtil.resolveClassPath(classLoader, "fallback"));
} finally {
Files.deleteIfExists(tempDir);
}
}

@Test
public void testResolveClassPathFallsBackForNestedJarUrl() throws Exception {
String fallback = "/tmp/fallback";
URL nestedJarUrl = createUrl("jar:nested:/tmp/apollo-app.jar/!BOOT-INF/classes/!/");
ClassLoader classLoader = classLoaderReturning(nestedJarUrl);

assertEquals(fallback, ClassLoaderUtil.resolveClassPath(classLoader, fallback));
}

@Test
public void testIsClassPresent() {
assertTrue(ClassLoaderUtil.isClassPresent("java.lang.String"));
Expand All @@ -50,4 +77,22 @@ public static class ClassWithInitializationError {
}
}
}
}

private ClassLoader classLoaderReturning(URL resource) {
return new ClassLoader(null) {
@Override
public URL getResource(String name) {
return resource;
}
};
}

private URL createUrl(String spec) throws Exception {
return new URL(null, spec, new URLStreamHandler() {
@Override
protected URLConnection openConnection(URL url) {
throw new UnsupportedOperationException();
}
});
}
}
Loading