77import javax .sql .DataSource ;
88import java .io .IOException ;
99import java .io .InputStream ;
10+ import java .net .URL ;
11+ import java .net .URLClassLoader ;
12+ import java .net .URLConnection ;
1013import java .nio .charset .StandardCharsets ;
1114import java .sql .Connection ;
1215import java .sql .PreparedStatement ;
@@ -128,7 +131,7 @@ private String readCore(ClassLoader classLoader, String version) throws SQLExcep
128131 private String readModule (PlexModule module , String resourceRoot , String version ) throws SQLException
129132 {
130133 String resource = resourceRoot + "/" + storageType .dialect ().migrationDirectory () + "/" + version + ".sql" ;
131- try (InputStream stream = module . getResource ( resource ))
134+ try (InputStream stream = openModuleResource ( module , resource ))
132135 {
133136 if (stream == null )
134137 {
@@ -142,6 +145,32 @@ private String readModule(PlexModule module, String resourceRoot, String version
142145 }
143146 }
144147
148+ /**
149+ * Opens a migration resource from the module's own jar.
150+ *
151+ * <p>A module class loader is parent-first with the Plex class loader as its
152+ * parent, and core ships migration scripts at the same
153+ * {@code db/migration/<dialect>/<version>.sql} paths a module uses. A plain
154+ * {@link PlexModule#getResource(String)} lookup therefore resolves to Plex's
155+ * core script instead of the module's own. {@link URLClassLoader#findResource}
156+ * searches only the module jar, so the module always reads its own migration.</p>
157+ */
158+ private InputStream openModuleResource (PlexModule module , String resource ) throws IOException
159+ {
160+ if (module .getClass ().getClassLoader () instanceof URLClassLoader moduleClassLoader )
161+ {
162+ URL url = moduleClassLoader .findResource (resource );
163+ if (url == null )
164+ {
165+ return null ;
166+ }
167+ URLConnection connection = url .openConnection ();
168+ connection .setUseCaches (false );
169+ return connection .getInputStream ();
170+ }
171+ return module .getResource (resource );
172+ }
173+
145174 private String replaceTableTokens (String script , Function <String , String > tableResolver ) throws SQLException
146175 {
147176 Matcher matcher = TABLE_TOKEN_PATTERN .matcher (script );
0 commit comments