diff --git a/resources/bundles/org.eclipse.core.resources/.classpath b/resources/bundles/org.eclipse.core.resources/.classpath index 3bf050a3e78..d522c679ebe 100644 --- a/resources/bundles/org.eclipse.core.resources/.classpath +++ b/resources/bundles/org.eclipse.core.resources/.classpath @@ -1,6 +1,6 @@ - + diff --git a/resources/bundles/org.eclipse.core.resources/.settings/org.eclipse.jdt.core.prefs b/resources/bundles/org.eclipse.core.resources/.settings/org.eclipse.jdt.core.prefs index 38430ddaad8..ffabc1f3715 100644 --- a/resources/bundles/org.eclipse.core.resources/.settings/org.eclipse.jdt.core.prefs +++ b/resources/bundles/org.eclipse.core.resources/.settings/org.eclipse.jdt.core.prefs @@ -17,9 +17,9 @@ org.eclipse.jdt.core.compiler.annotation.nullable=org.eclipse.jdt.annotation.Nul org.eclipse.jdt.core.compiler.annotation.nullanalysis=disabled org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled org.eclipse.jdt.core.compiler.codegen.methodParameters=do not generate -org.eclipse.jdt.core.compiler.codegen.targetPlatform=17 +org.eclipse.jdt.core.compiler.codegen.targetPlatform=25 org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve -org.eclipse.jdt.core.compiler.compliance=17 +org.eclipse.jdt.core.compiler.compliance=25 org.eclipse.jdt.core.compiler.debug.lineNumber=generate org.eclipse.jdt.core.compiler.debug.localVariable=generate org.eclipse.jdt.core.compiler.debug.sourceFile=generate @@ -127,7 +127,7 @@ org.eclipse.jdt.core.compiler.problem.unusedTypeParameter=ignore org.eclipse.jdt.core.compiler.problem.unusedWarningToken=warning org.eclipse.jdt.core.compiler.problem.varargsArgumentNeedCast=warning org.eclipse.jdt.core.compiler.release=enabled -org.eclipse.jdt.core.compiler.source=17 +org.eclipse.jdt.core.compiler.source=25 org.eclipse.jdt.core.formatter.align_assignment_statements_on_columns=false org.eclipse.jdt.core.formatter.align_fields_grouping_blank_lines=2147483647 org.eclipse.jdt.core.formatter.align_type_members_on_columns=false diff --git a/resources/bundles/org.eclipse.core.resources/META-INF/MANIFEST.MF b/resources/bundles/org.eclipse.core.resources/META-INF/MANIFEST.MF index 82730f06304..f690809eed9 100644 --- a/resources/bundles/org.eclipse.core.resources/META-INF/MANIFEST.MF +++ b/resources/bundles/org.eclipse.core.resources/META-INF/MANIFEST.MF @@ -32,7 +32,6 @@ Require-Bundle: org.eclipse.ant.core;bundle-version="[3.7.0,4.0.0)";resolution:= Bundle-ActivationPolicy: lazy Service-Component: OSGI-INF/org.eclipse.core.internal.resources.CheckMissingNaturesListener.xml, OSGI-INF/org.eclipse.core.internal.resources.ResourceChangeListenerRegistrar.xml -Bundle-RequiredExecutionEnvironment: JavaSE-17 +Bundle-RequiredExecutionEnvironment: JavaSE-25 Automatic-Module-Name: org.eclipse.core.resources -Import-Package: com.sun.jna;version="[5.17.0,6.0.0)", - org.eclipse.osgi.service.datalocation;version="[1.4.0,2.0.0)" +Import-Package: org.eclipse.osgi.service.datalocation;version="[1.4.0,2.0.0)" diff --git a/resources/bundles/org.eclipse.core.resources/build.properties b/resources/bundles/org.eclipse.core.resources/build.properties index 4b9091f7478..dca782aa727 100644 --- a/resources/bundles/org.eclipse.core.resources/build.properties +++ b/resources/bundles/org.eclipse.core.resources/build.properties @@ -30,3 +30,5 @@ extra.ant_tasks/resources-ant.jar = platform:/plugin/org.apache.ant, platform:/p jars.extra.classpath = platform:/plugin/org.apache.ant/lib/ant.jar javacWarnings..=-unavoidableGenericProblems javacWarnings.ant_tasks/resources-ant.jar=-unavoidableGenericProblems +javacSource=25 +javacTarget=25 diff --git a/resources/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/resources/refresh/win32/Win32Natives.java b/resources/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/resources/refresh/win32/Win32Natives.java index a34b0c82d9e..9c63398200b 100644 --- a/resources/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/resources/refresh/win32/Win32Natives.java +++ b/resources/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/resources/refresh/win32/Win32Natives.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2002, 2024 IBM Corporation and others. + * Copyright (c) 2002, 2025 IBM Corporation and others. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 @@ -12,13 +12,19 @@ * IBM - Initial API and implementation * Mikael Barbero (Eclipse Foundation) - 286681 handle WAIT_ABANDONED_0 return value * Hannes Wellmann - Migrate Win32Natives to use JNA instead of JNI to avoid native binaries and platform-specific fragments + * Contributors - Migrate Win32Natives to use FFM (Foreign Function & Memory) API *******************************************************************************/ package org.eclipse.core.internal.resources.refresh.win32; -import com.sun.jna.Native; -import com.sun.jna.NativeLibrary; -import com.sun.jna.WString; +import java.lang.foreign.Arena; +import java.lang.foreign.FunctionDescriptor; +import java.lang.foreign.Linker; +import java.lang.foreign.MemorySegment; +import java.lang.foreign.SymbolLookup; +import java.lang.foreign.ValueLayout; +import java.lang.invoke.MethodHandle; +import java.nio.charset.StandardCharsets; /** * Hooks for native methods involved with win32 auto-refresh callbacks. @@ -95,33 +101,111 @@ public class Win32Natives { public static final int FILE_NOTIFY_CHANGE_LAST_WRITE = 0x10; // winnt.h private static class WindowsH { + private static final Linker LINKER = Linker.nativeLinker(); + private static final SymbolLookup KERNEL32; + + // Method handles for Kernel32 functions + private static final MethodHandle FindFirstChangeNotificationW; + private static final MethodHandle FindCloseChangeNotification; + private static final MethodHandle FindNextChangeNotification; + private static final MethodHandle WaitForMultipleObjects; + private static final MethodHandle GetLastError; + static { - Native.register(NativeLibrary - .getInstance("Kernel32" /* , W32APIOptions.DEFAULT_OPTIONS < type-conversion unnecessary> */)); //$NON-NLS-1$ + try { + // Load Kernel32 library + KERNEL32 = SymbolLookup.libraryLookup("Kernel32", Arena.global()); + + // WinNT's type 'HANDLE' is expressed as a pointer (long on 64-bit, int on 32-bit) + // We use ADDRESS layout which represents a native pointer + + // HANDLE FindFirstChangeNotificationW(LPCWSTR lpPathName, BOOL bWatchSubtree, DWORD dwNotifyFilter) + FindFirstChangeNotificationW = LINKER.downcallHandle( + KERNEL32.find("FindFirstChangeNotificationW").orElseThrow(), + FunctionDescriptor.of(ValueLayout.ADDRESS, ValueLayout.ADDRESS, ValueLayout.JAVA_INT, ValueLayout.JAVA_INT) + ); + + // BOOL FindCloseChangeNotification(HANDLE hChangeHandle) + FindCloseChangeNotification = LINKER.downcallHandle( + KERNEL32.find("FindCloseChangeNotification").orElseThrow(), + FunctionDescriptor.of(ValueLayout.JAVA_INT, ValueLayout.ADDRESS) + ); + + // BOOL FindNextChangeNotification(HANDLE hChangeHandle) + FindNextChangeNotification = LINKER.downcallHandle( + KERNEL32.find("FindNextChangeNotification").orElseThrow(), + FunctionDescriptor.of(ValueLayout.JAVA_INT, ValueLayout.ADDRESS) + ); + + // DWORD WaitForMultipleObjects(DWORD nCount, HANDLE *lpHandles, BOOL bWaitAll, DWORD dwMilliseconds) + WaitForMultipleObjects = LINKER.downcallHandle( + KERNEL32.find("WaitForMultipleObjects").orElseThrow(), + FunctionDescriptor.of(ValueLayout.JAVA_INT, ValueLayout.JAVA_INT, ValueLayout.ADDRESS, ValueLayout.JAVA_INT, ValueLayout.JAVA_INT) + ); + + // DWORD GetLastError(void) + GetLastError = LINKER.downcallHandle( + KERNEL32.find("GetLastError").orElseThrow(), + FunctionDescriptor.of(ValueLayout.JAVA_INT) + ); + } catch (Throwable t) { + throw new ExceptionInInitializerError(t); + } } - // Direct-mappings are faster than interface-mappings - // and avoiding type-conversions is faster again. - // https://github.com/java-native-access/jna/blob/master/www/FunctionalDescription.md#direct-mapping - - // WinNT's type 'HANDLE is expressed as long - // (in winnt.h it is defined as 'typedef HANDLE *PHANDLE;') // Methods from fileapi.h header + + static MemorySegment FindFirstChangeNotificationW(MemorySegment lpPathName, int bWatchSubtree, int dwNotifyFilter) { + try { + return (MemorySegment) FindFirstChangeNotificationW.invokeExact(lpPathName, bWatchSubtree, dwNotifyFilter); + } catch (Throwable t) { + throw new RuntimeException("Failed to call FindFirstChangeNotificationW", t); + } + } - static native long FindFirstChangeNotificationW(WString lpPathName, int bWatchSubtree, int dwNotifyFilter); - - static native int FindCloseChangeNotification(long hChangeHandle); + static int FindCloseChangeNotification(MemorySegment hChangeHandle) { + try { + return (int) FindCloseChangeNotification.invokeExact(hChangeHandle); + } catch (Throwable t) { + throw new RuntimeException("Failed to call FindCloseChangeNotification", t); + } + } - static native int FindNextChangeNotification(long hChangeHandle); + static int FindNextChangeNotification(MemorySegment hChangeHandle) { + try { + return (int) FindNextChangeNotification.invokeExact(hChangeHandle); + } catch (Throwable t) { + throw new RuntimeException("Failed to call FindNextChangeNotification", t); + } + } // Methods from synchapi.h - static native int WaitForMultipleObjects(int nCount, long[] lpHandles, int bWaitAll, int dwMilliseconds); + static int WaitForMultipleObjects(int nCount, MemorySegment lpHandles, int bWaitAll, int dwMilliseconds) { + try { + return (int) WaitForMultipleObjects.invokeExact(nCount, lpHandles, bWaitAll, dwMilliseconds); + } catch (Throwable t) { + throw new RuntimeException("Failed to call WaitForMultipleObjects", t); + } + } + + static int GetLastError() { + try { + return (int) GetLastError.invokeExact(); + } catch (Throwable t) { + throw new RuntimeException("Failed to call GetLastError", t); + } + } - // direct type conversion methods + // Helper methods for type conversion - static WString fromString(String value) { - return new WString(value); + static MemorySegment toWideString(Arena arena, String value) { + // Convert Java String to null-terminated wide string (UTF-16LE) + // In Java 21, we need to manually encode and allocate + byte[] bytes = (value + "\0").getBytes(StandardCharsets.UTF_16LE); + MemorySegment segment = arena.allocate(bytes.length); + segment.asByteBuffer().put(bytes); + return segment; } static int fromBoolean(boolean value) { @@ -156,9 +240,12 @@ static boolean toBoolean(int value) { * ERROR_INVALID_HANDLE if the attempt fails. */ public static long FindFirstChangeNotification(String lpPathName, boolean bWatchSubtree, int dwNotifyFilter) { - WString wPathName = WindowsH - .fromString(!lpPathName.startsWith(LONG_PATH_PREFIX) ? LONG_PATH_PREFIX + lpPathName : lpPathName); - return WindowsH.FindFirstChangeNotificationW(wPathName, WindowsH.fromBoolean(bWatchSubtree), dwNotifyFilter); + String fullPath = !lpPathName.startsWith(LONG_PATH_PREFIX) ? LONG_PATH_PREFIX + lpPathName : lpPathName; + try (Arena arena = Arena.ofConfined()) { + MemorySegment wPathName = WindowsH.toWideString(arena, fullPath); + MemorySegment handle = WindowsH.FindFirstChangeNotificationW(wPathName, WindowsH.fromBoolean(bWatchSubtree), dwNotifyFilter); + return handle.address(); + } } /** @@ -171,7 +258,8 @@ public static long FindFirstChangeNotification(String lpPathName, boolean bWatch * otherwise. */ public static boolean FindCloseChangeNotification(long hChangeHandle) { - return WindowsH.toBoolean(WindowsH.FindCloseChangeNotification(hChangeHandle)); + MemorySegment handle = MemorySegment.ofAddress(hChangeHandle); + return WindowsH.toBoolean(WindowsH.FindCloseChangeNotification(handle)); } /** @@ -183,7 +271,8 @@ public static boolean FindCloseChangeNotification(long hChangeHandle) { * @return boolean true if the method succeeds, false otherwise. */ public static boolean FindNextChangeNotification(long hChangeHandle) { - return WindowsH.toBoolean(WindowsH.FindNextChangeNotification(hChangeHandle)); + MemorySegment handle = MemorySegment.ofAddress(hChangeHandle); + return WindowsH.toBoolean(WindowsH.FindNextChangeNotification(handle)); } /** @@ -207,7 +296,15 @@ public static boolean FindNextChangeNotification(long hChangeHandle) { * function fails. */ public static int WaitForMultipleObjects(int nCount, long[] lpHandles, boolean bWaitAll, int dwMilliseconds) { - return WindowsH.WaitForMultipleObjects(nCount, lpHandles, WindowsH.fromBoolean(bWaitAll), dwMilliseconds); + try (Arena arena = Arena.ofConfined()) { + // Allocate memory for array of handles (array of pointers) + long arraySize = ValueLayout.ADDRESS.byteSize() * nCount; + MemorySegment handlesArray = arena.allocate(arraySize, ValueLayout.ADDRESS.byteAlignment()); + for (int i = 0; i < nCount; i++) { + handlesArray.setAtIndex(ValueLayout.ADDRESS, i, MemorySegment.ofAddress(lpHandles[i])); + } + return WindowsH.WaitForMultipleObjects(nCount, handlesArray, WindowsH.fromBoolean(bWaitAll), dwMilliseconds); + } } /** @@ -215,7 +312,7 @@ public static int WaitForMultipleObjects(int nCount, long[] lpHandles, boolean b * @return int the last error */ public static int GetLastError() { - return Native.getLastError(); + return WindowsH.GetLastError(); } }