Prefer Java 8+ runtime for MfApi; Sonic JRE is often too old.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-07-24 09:36:45 +02:00
co-authored by Cursor
parent 5f216badca
commit eba8e7b4d6
@@ -178,8 +178,28 @@ public sealed class SonicMfApiExecutor
private async Task<(bool Ok, string? JavaExe, string? ClassDir, string? Classpath, string? Error)>
PrepareToolAsync(CancellationToken cancellationToken)
{
// Tool-Bytecode ist Java 8 (major 52). Sonic-mitgelieferte JREs sind oft Java 6/7 → unbrauchbar.
// Deshalb: Runtime mit major>=52 bevorzugen (PATH/JAVA_HOME/Registry), Libs weiter aus SonicHome.
const int minClassMajor = 52;
JavaDiscoveryResult javaResult = DiscoverJava();
string? javaExe = javaResult.JavaExe;
int runtimeMajor = javaExe is null
? 0
: await GetJavaClassMajorAsync(javaExe, cancellationToken);
if (javaExe is null || runtimeMajor < minClassMajor)
{
(string? newerJava, int newerMajor, List<string> probed) =
await FindJavaWithMinimumMajorAsync(minClassMajor, cancellationToken);
if (newerJava is not null)
{
javaExe = newerJava;
runtimeMajor = newerMajor;
javaResult.CheckedPaths.Add($"UPGRADE:RuntimeJava8+={newerJava} major={newerMajor}");
}
}
if (javaExe is null)
{
string sonicHome = string.IsNullOrWhiteSpace(_connection.SonicHome)
@@ -188,20 +208,22 @@ public sealed class SonicMfApiExecutor
string checkedList = javaResult.CheckedPaths.Count == 0
? "(keine Kandidaten gesammelt)"
: string.Join("\n - ", javaResult.CheckedPaths.Take(MaxCheckedPathsInError));
if (javaResult.CheckedPaths.Count > MaxCheckedPathsInError)
{
checkedList += $"\n - … (+{javaResult.CheckedPaths.Count - MaxCheckedPathsInError} weitere)";
}
return (false, null, null, null,
"Java nicht gefunden.\n" +
$"Verwendetes SonicHome: '{sonicHome}'\n" +
$"SonicHome existiert: {(Directory.Exists(sonicHome) ? "ja" : "nein")}\n" +
"Konfiguration: SonicConnection.JavaHome / JavaPath, sonst Auto-Suche " +
"(JAVA_HOME/JRE_HOME, setenv.bat, rekursiv unter SonicHome, MQ/ESB-Nachbarn, Registry, where).\n" +
"Geprüfte Pfade:\n - " + checkedList + "\n" +
"Tipp: JavaHome oder JavaPath in appsettings auf die echte java.exe setzen " +
"(z.B. C:\\Sonic\\MQ10.0\\jre\\bin\\java.exe).");
"Konfiguration: JavaPath/JavaHome auf eine Java-8+-Runtime setzen.\n" +
"Geprüfte Pfade:\n - " + checkedList);
}
if (runtimeMajor < minClassMajor)
{
return (false, null, null, null,
"Gefundene Java-Runtime ist zu alt für SonicMfContainerTool (braucht Java 8 / major 52).\n" +
$"Aktuell: {javaExe} (class major={runtimeMajor}).\n" +
"Die JRE unter SonicHome ist oft Java 6/7 bitte Java 8+ installieren und in appsettings setzen:\n" +
" \"JavaPath\": \"C:\\\\Program Files\\\\Java\\\\jre1.8.0_xxx\\\\bin\\\\java.exe\"\n" +
"Sonic-Client-JARs bleiben unter SonicHome\\lib.");
}
(string? libDir, string? libError) = ResolveLibDirectoryDetailed();
@@ -210,9 +232,6 @@ public sealed class SonicMfApiExecutor
return (false, null, null, null, libError);
}
int runtimeMajor = await GetJavaClassMajorAsync(javaExe, cancellationToken);
// Sonic/SMC nutzt typisch Java 8 (major 52). Nie mit höherer Class-Version starten.
// Vorcompilierte .class/.jar nur nutzen, wenn Class-Version zur Runtime passt.
if (TryResolvePrebuiltTool(runtimeMajor, out string? prebuiltDir, out string? prebuiltEntry, out string? prebuiltError)
&& prebuiltDir is not null && prebuiltEntry is not null)
@@ -385,32 +404,119 @@ public sealed class SonicMfApiExecutor
using Process p = new() { StartInfo = psi };
if (!p.Start())
{
return 52; // Sonic-Default Java 8
return 0;
}
string err = await p.StandardError.ReadToEndAsync(cancellationToken);
string output = await p.StandardOutput.ReadToEndAsync(cancellationToken);
await p.WaitForExitAsync(cancellationToken);
string text = (err + "\n" + output).ToLowerInvariant();
if (text.Contains("version \"1.8") || text.Contains("version \"8"))
return ParseJavaVersionToClassMajor(err + "\n" + output);
}
catch
{
return 52;
return 0;
}
}
Match m = Regex.Match(text, @"version ""(\d+)");
if (m.Success && int.TryParse(m.Groups[1].Value, out int major) && major >= 9)
private static int ParseJavaVersionToClassMajor(string versionText)
{
// Java 9+ class major = 44 + version => 9→53, 11→55, 17→61, 21→65
return 44 + major;
string text = versionText.ToLowerInvariant();
// 1.8.x → 52, 1.7.x → 51, 1.6.x → 50
Match legacy = Regex.Match(text, @"version\s+""1\.(\d+)");
if (legacy.Success && int.TryParse(legacy.Groups[1].Value, out int minor))
{
return 44 + minor; // 1.6→50, 1.7→51, 1.8→52
}
Match modern = Regex.Match(text, @"version\s+""(\d+)");
if (modern.Success && int.TryParse(modern.Groups[1].Value, out int major) && major >= 9)
{
return 44 + major; // 9→53 … 21→65
}
return 0;
}
/// <summary>
/// Sucht eine java.exe mit mindestens der gewünschten Class-Major-Version
/// (für Tool-Bytecode Java 8 = 52), unabhängig von der alten Sonic-JRE.
/// </summary>
private async Task<(string? JavaExe, int Major, List<string> Probed)> FindJavaWithMinimumMajorAsync(
int minMajor,
CancellationToken cancellationToken)
{
List<string> probed = [];
List<string> candidates = [];
void AddCandidate(string? path)
{
if (string.IsNullOrWhiteSpace(path) || !File.Exists(path))
{
return;
}
string full = Path.GetFullPath(path);
if (!candidates.Contains(full, StringComparer.OrdinalIgnoreCase))
{
candidates.Add(full);
}
}
foreach (string? configured in new[] { _connection.JavaPath, _connection.JavaHome })
{
if (string.IsNullOrWhiteSpace(configured)) continue;
AddCandidate(ResolveToolFromConfiguredPath(configured, JavaExeName, probed));
}
foreach (string envName in new[] { "JAVA_HOME", "JRE_HOME", "JDK_HOME" })
{
AddCandidate(ResolveJavaFromHomeDir(Environment.GetEnvironmentVariable(envName), probed, envName));
}
AddCandidate(FindOnPath(JavaExeName, probed));
AddCandidate(FindOnPath("java", probed));
AddCandidate(FindJavaInWindowsRegistry(probed));
AddCandidate(FindJavaViaWhereExe(probed));
AddCandidate(FindJavaInCommonInstallLocations(probed));
// Program Files Java/Adoptium/Temurin grob scannen
foreach (string root in new[]
{
Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles),
Environment.GetFolderPath(Environment.SpecialFolder.ProgramFilesX86),
@"C:\Program Files\Eclipse Adoptium",
@"C:\Program Files\Java",
@"C:\Program Files\Microsoft",
@"C:\Program Files\Amazon Corretto"
})
{
if (!Directory.Exists(root)) continue;
try
{
foreach (string javaExe in Directory.EnumerateFiles(root, "java.exe", SearchOption.AllDirectories)
.Take(40))
{
AddCandidate(javaExe);
}
}
catch
{
// ignore
}
}
return 52;
foreach (string candidate in candidates)
{
int major = await GetJavaClassMajorAsync(candidate, cancellationToken);
probed.Add($"{candidate} => major={major}");
if (major >= minMajor)
{
return (candidate, major, probed);
}
}
return (null, 0, probed);
}
private static bool SupportsJavacRelease8(string javacPath)