From c228b87e90ca08585db94d513b6b0c883d291afb Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 31 May 2026 15:15:58 +0000 Subject: [PATCH 1/2] Add ClassDescriptor migration: infrastructure + 5 migrated host classes --- .../htmlunit/javascript/JavaScriptEngine.java | 38 +++++++++ .../AbstractJavaScriptConfiguration.java | 50 +++++++++++ .../configuration/ClassConfiguration.java | 29 +++++++ .../HtmlUnitClassDescriptor.java | 85 +++++++++++++++++++ .../JavaScriptConfiguration.java | 19 ++++- .../org/htmlunit/javascript/host/BarProp.java | 46 +++++++--- .../org/htmlunit/javascript/host/Gamepad.java | 46 +++++++--- .../javascript/host/GamepadButton.java | 46 +++++++--- .../javascript/host/dom/IdleDeadline.java | 46 +++++++--- .../host/geo/GeolocationCoordinates.java | 69 +++++++++++---- 10 files changed, 415 insertions(+), 59 deletions(-) create mode 100644 src/main/java/org/htmlunit/javascript/configuration/HtmlUnitClassDescriptor.java diff --git a/src/main/java/org/htmlunit/javascript/JavaScriptEngine.java b/src/main/java/org/htmlunit/javascript/JavaScriptEngine.java index 101c5f66e0..d234c28c4b 100644 --- a/src/main/java/org/htmlunit/javascript/JavaScriptEngine.java +++ b/src/main/java/org/htmlunit/javascript/JavaScriptEngine.java @@ -41,12 +41,14 @@ import org.htmlunit.corejs.javascript.AbstractEcmaObjectOperations; import org.htmlunit.corejs.javascript.BaseFunction; import org.htmlunit.corejs.javascript.Callable; +import org.htmlunit.corejs.javascript.ClassDescriptor; import org.htmlunit.corejs.javascript.Context; import org.htmlunit.corejs.javascript.ContextAction; import org.htmlunit.corejs.javascript.ContextFactory; import org.htmlunit.corejs.javascript.EcmaError; import org.htmlunit.corejs.javascript.Function; import org.htmlunit.corejs.javascript.FunctionObject; +import org.htmlunit.corejs.javascript.JSFunction; import org.htmlunit.corejs.javascript.JavaScriptException; import org.htmlunit.corejs.javascript.NativeArray; import org.htmlunit.corejs.javascript.NativeArrayIterator; @@ -59,6 +61,7 @@ import org.htmlunit.corejs.javascript.ScriptableObject; import org.htmlunit.corejs.javascript.StackStyle; import org.htmlunit.corejs.javascript.Symbol; +import org.htmlunit.corejs.javascript.SymbolKey; import org.htmlunit.corejs.javascript.TopLevel; import org.htmlunit.corejs.javascript.VarScope; import org.htmlunit.corejs.javascript.WithScope; @@ -325,6 +328,41 @@ public static void configureGlobalThis( scopeContructorFunctionObject.setPrototype(ctorPrototypesPerJSName.get(extendedClassName)); } } + else if (config.getDescriptor() != null) { + // Descriptor-based path (ClassDescriptor API) + final HtmlUnitScriptable classPrototype = config.getHostClass().getDeclaredConstructor().newInstance(); + classPrototype.setParentScope(scope); + classPrototype.setClassName(jsClassName); + + // buildConstructor wires up all methods/properties, sets proto.__proto__ to Object.prototype, + // and registers the constructor in the scope (which routes to globalThis via TopLevel.put) + final JSFunction ctor = config.getDescriptor().buildConstructor( + Context.getCurrentContext(), scope, classPrototype, false); + ctorPrototypesPerJSName.put(jsClassName, ctor); + + // Override proto chain after buildConstructor (it defaults to Object.prototype) + if (extendedClassName != null) { + classPrototype.setPrototype(prototypesPerJSName.get(extendedClassName)); + ctor.setPrototype(ctorPrototypesPerJSName.get(extendedClassName)); + } + + prototypes.put(config.getHostClass(), classPrototype); + prototypesPerJSName.put(jsClassName, classPrototype); + + // Add Symbol.toStringTag to match the annotation-based setup in process() + ScriptableObject.defineProperty(classPrototype, SymbolKey.TO_STRING_TAG, jsClassName, + ScriptableObject.DONTENUM | ScriptableObject.READONLY); + + if (!config.isJsObject()) { + // buildConstructor registers the ctor in the scope (→ globalThis), so remove it + globalThis.delete(jsClassName); + } + + final String alias = config.getJsConstructorAlias(); + if (alias != null) { + ScriptableObject.defineProperty(globalThis, alias, ctor, ScriptableObject.DONTENUM); + } + } else { final HtmlUnitScriptable classPrototype = configureClass(config, scope); prototypes.put(config.getHostClass(), classPrototype); diff --git a/src/main/java/org/htmlunit/javascript/configuration/AbstractJavaScriptConfiguration.java b/src/main/java/org/htmlunit/javascript/configuration/AbstractJavaScriptConfiguration.java index 93729bffbf..a05cbfbc80 100644 --- a/src/main/java/org/htmlunit/javascript/configuration/AbstractJavaScriptConfiguration.java +++ b/src/main/java/org/htmlunit/javascript/configuration/AbstractJavaScriptConfiguration.java @@ -72,6 +72,22 @@ protected AbstractJavaScriptConfiguration(final BrowserVersion browser, final Cl } } } + + final SupportedBrowser expectedBrowser = toSupportedBrowser(browser); + for (final HtmlUnitClassDescriptor descriptor : getDescriptors()) { + final org.htmlunit.corejs.javascript.ClassDescriptor classDescriptor = + descriptor.forBrowser(expectedBrowser); + if (classDescriptor != null) { + final ClassConfiguration config = new ClassConfiguration( + descriptor.getHostClass(), + descriptor.getDomClasses(), + descriptor.isJsObject(), + null, + descriptor.getExtendedClassName(), + classDescriptor); + configuration_.add(config); + } + } } /** @@ -79,6 +95,40 @@ protected AbstractJavaScriptConfiguration(final BrowserVersion browser, final Cl */ protected abstract Class[] getClasses(); + /** + * Returns the descriptor-based host classes registered by this configuration. + * Subclasses override this to return their migrated descriptors. + * + * @return the descriptors, never {@code null} + */ + protected HtmlUnitClassDescriptor[] getDescriptors() { + return new HtmlUnitClassDescriptor[0]; + } + + /** + * Maps a {@link BrowserVersion} to the corresponding {@link SupportedBrowser} constant. + * + * @param browserVersion the browser version + * @return the matching {@link SupportedBrowser} + */ + private static SupportedBrowser toSupportedBrowser(final BrowserVersion browserVersion) { + if (browserVersion != null) { + if (browserVersion.isChrome()) { + return CHROME; + } + if (browserVersion.isEdge()) { + return EDGE; + } + if (browserVersion.isFirefoxESR()) { + return FF_ESR; + } + if (browserVersion.isFirefox()) { + return FF; + } + } + return CHROME; + } + /** * Gets all the configurations. * @return the class configurations diff --git a/src/main/java/org/htmlunit/javascript/configuration/ClassConfiguration.java b/src/main/java/org/htmlunit/javascript/configuration/ClassConfiguration.java index 7923851659..dbdea7f71f 100644 --- a/src/main/java/org/htmlunit/javascript/configuration/ClassConfiguration.java +++ b/src/main/java/org/htmlunit/javascript/configuration/ClassConfiguration.java @@ -22,6 +22,7 @@ import java.util.List; import java.util.Map; +import org.htmlunit.corejs.javascript.ClassDescriptor; import org.htmlunit.corejs.javascript.ScriptableObject; import org.htmlunit.corejs.javascript.Symbol; import org.htmlunit.javascript.HtmlUnitScriptable; @@ -54,6 +55,7 @@ public final class ClassConfiguration { private final Class[] domClasses_; private final boolean jsObject_; private final String className_; + private final ClassDescriptor descriptor_; /** * Constructor. @@ -66,6 +68,22 @@ public final class ClassConfiguration { */ public ClassConfiguration(final Class hostClass, final Class[] domClasses, final boolean jsObject, final String className, final String extendedClassName) { + this(hostClass, domClasses, jsObject, className, extendedClassName, null); + } + + /** + * Constructor for descriptor-based host classes. + * + * @param hostClass - the class implementing this functionality + * @param domClasses the DOM classes that this object supports + * @param jsObject boolean flag for if this object is a JavaScript object + * @param className the class name, can be null + * @param extendedClassName the extended class name + * @param descriptor the {@link ClassDescriptor} to use for wiring, or {@code null} for annotation-based setup + */ + public ClassConfiguration(final Class hostClass, final Class[] domClasses, + final boolean jsObject, final String className, final String extendedClassName, + final ClassDescriptor descriptor) { hostClass_ = hostClass; hostClassSimpleName_ = hostClass_.getSimpleName(); jsObject_ = jsObject; @@ -77,6 +95,7 @@ public ClassConfiguration(final Class hostClass, f className_ = className; } extendedClassName_ = extendedClassName; + descriptor_ = descriptor; } void setJSConstructor(final String name, final Member jsConstructor) { @@ -308,6 +327,16 @@ public String getClassName() { return className_; } + /** + * Returns the {@link ClassDescriptor} for this class, or {@code null} if this class + * uses the annotation-based setup. + * + * @return the descriptor, or {@code null} + */ + public ClassDescriptor getDescriptor() { + return descriptor_; + } + /** * Class used to contain the property information if the property is readable, writable and the * methods that implement the get and set functions. diff --git a/src/main/java/org/htmlunit/javascript/configuration/HtmlUnitClassDescriptor.java b/src/main/java/org/htmlunit/javascript/configuration/HtmlUnitClassDescriptor.java new file mode 100644 index 0000000000..bc3ed17ac9 --- /dev/null +++ b/src/main/java/org/htmlunit/javascript/configuration/HtmlUnitClassDescriptor.java @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2002-2026 Gargoyle Software Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.htmlunit.javascript.configuration; + +import org.htmlunit.corejs.javascript.ClassDescriptor; +import org.htmlunit.javascript.HtmlUnitScriptable; + +/** + * Descriptor-based registration for a JavaScript host class. + * + *

This interface is part of the incremental migration from the annotation-based + * setup ({@code @JsxClass}, {@code @JsxFunction}, etc.) to Rhino's + * {@link ClassDescriptor} API. Both paths can coexist during the transition.

+ * + *

Classes that have been migrated implement this interface as a static + * {@code HTMLUNIT_DESCRIPTOR} constant and no longer carry {@code @Jsx*} annotations. + * They are registered via {@link AbstractJavaScriptConfiguration#getDescriptors()} + * rather than being listed in the {@code getClasses()} array.

+ * + * @author Ronald Brill + */ +public interface HtmlUnitClassDescriptor { + + /** + * Returns the {@link ClassDescriptor} for the given browser, or {@code null} + * if this class is not supported by that browser. + * + * @param browser the target browser + * @return the descriptor, or {@code null} if unsupported + */ + ClassDescriptor forBrowser(SupportedBrowser browser); + + /** + * Returns the host class that implements this JavaScript object. + * + * @return the host class + */ + Class getHostClass(); + + /** + * Returns the DOM classes that this JavaScript object wraps. + * May be an empty array if the object has no DOM counterpart. + * + * @return the DOM classes, never {@code null} + */ + Class[] getDomClasses(); + + /** + * Returns whether this object is visible as a named property of the global object + * (i.e. {@code window.ClassName} is defined). + * + * @return {@code true} if the constructor is exposed on the global object + */ + boolean isJsObject(); + + /** + * Returns the simple name of the parent JavaScript class, or an empty string + * if the class does not extend another HtmlUnit scriptable class. + * + * @return the extended class name, never {@code null} + */ + String getExtendedClassName(); + + /** + * Returns an additional name under which the constructor should be registered + * on the global object, or {@code null} if no alias is needed. + * + * @return the alias, or {@code null} + */ + default String getJsConstructorAlias() { + return null; + } +} diff --git a/src/main/java/org/htmlunit/javascript/configuration/JavaScriptConfiguration.java b/src/main/java/org/htmlunit/javascript/configuration/JavaScriptConfiguration.java index eb213ba974..8ec8a10682 100644 --- a/src/main/java/org/htmlunit/javascript/configuration/JavaScriptConfiguration.java +++ b/src/main/java/org/htmlunit/javascript/configuration/JavaScriptConfiguration.java @@ -544,17 +544,17 @@ public final class JavaScriptConfiguration extends AbstractJavaScriptConfigurati static final Class[] CLASSES_ = new Class[] { // level 1 AbortController.class, AbstractRange.class, Atomics.class, AudioBuffer.class, AudioListener.class, - AudioParam.class, BarProp.class, Blob.class, CSS.class, CSSRule.class, CSSRuleList.class, + AudioParam.class, Blob.class, CSS.class, CSSRule.class, CSSRuleList.class, CSSStyleDeclaration.class, Cache.class, CacheStorage.class, CanvasGradient.class, CanvasPattern.class, CanvasRenderingContext2D.class, CaretPosition.class, Credential.class, CredentialsContainer.class, Crypto.class, CryptoKey.class, CustomElementRegistry.class, DOMError.class, DOMException.class, DOMImplementation.class, DOMMatrixReadOnly.class, DOMParser.class, DOMPointReadOnly.class, DOMRectList.class, DOMRectReadOnly.class, DOMStringList.class, DOMStringMap.class, DOMTokenList.class, DataTransfer.class, DataTransferItem.class, DataTransferItemList.class, Event.class, EventTarget.class, External.class, FileList.class, FileSystem.class, - FileSystemDirectoryReader.class, FileSystemEntry.class, FontFace.class, FormData.class, Gamepad.class, - GamepadButton.class, Geolocation.class, GeolocationCoordinates.class, GeolocationPosition.class, + FileSystemDirectoryReader.class, FileSystemEntry.class, FontFace.class, FormData.class, + Geolocation.class, GeolocationPosition.class, GeolocationPositionError.class, HTMLOptionsCollection.class, Headers.class, History.class, IDBCursor.class, - IDBFactory.class, IDBIndex.class, IDBKeyRange.class, IDBObjectStore.class, IdleDeadline.class, + IDBFactory.class, IDBIndex.class, IDBKeyRange.class, IDBObjectStore.class, ImageBitmap.class, ImageBitmapRenderingContext.class, ImageData.class, InputDeviceCapabilities.class, IntersectionObserver.class, IntersectionObserverEntry.class, KeyframeEffect.class, Location.class, MIDIInputMap.class, MIDIOutputMap.class, MediaDeviceInfo.class, MediaError.class, MediaKeyStatusMap.class, @@ -710,6 +710,17 @@ protected Class[] getClasses() { return CLASSES_; } + @Override + protected HtmlUnitClassDescriptor[] getDescriptors() { + return new HtmlUnitClassDescriptor[] { + BarProp.HTMLUNIT_DESCRIPTOR, + Gamepad.HTMLUNIT_DESCRIPTOR, + GamepadButton.HTMLUNIT_DESCRIPTOR, + GeolocationCoordinates.HTMLUNIT_DESCRIPTOR, + IdleDeadline.HTMLUNIT_DESCRIPTOR, + }; + } + /** * @return the configuration of the globalThis class */ diff --git a/src/main/java/org/htmlunit/javascript/host/BarProp.java b/src/main/java/org/htmlunit/javascript/host/BarProp.java index 811461f829..592f25c42f 100644 --- a/src/main/java/org/htmlunit/javascript/host/BarProp.java +++ b/src/main/java/org/htmlunit/javascript/host/BarProp.java @@ -14,9 +14,11 @@ */ package org.htmlunit.javascript.host; +import org.htmlunit.corejs.javascript.ClassDescriptor; +import org.htmlunit.corejs.javascript.Undefined; import org.htmlunit.javascript.HtmlUnitScriptable; -import org.htmlunit.javascript.configuration.JsxClass; -import org.htmlunit.javascript.configuration.JsxConstructor; +import org.htmlunit.javascript.configuration.HtmlUnitClassDescriptor; +import org.htmlunit.javascript.configuration.SupportedBrowser; /** * A JavaScript object for {@code BarProp}. @@ -24,14 +26,38 @@ * @author Ahmed Ashour * @author Ronald Brill */ -@JsxClass public class BarProp extends HtmlUnitScriptable { - /** - * JavaScript constructor. - */ - @JsxConstructor - public void jsConstructor() { - // nothing to do - } + /** Descriptor for registering this class with the JavaScript engine. */ + public static final HtmlUnitClassDescriptor HTMLUNIT_DESCRIPTOR = new HtmlUnitClassDescriptor() { + + private static final ClassDescriptor DESCRIPTOR_ = new ClassDescriptor.Builder("BarProp", 0, + (cx, f, callerObj, scope, thisObj, args) -> Undefined.instance) + .build(); + + @Override + public ClassDescriptor forBrowser(final SupportedBrowser browser) { + return DESCRIPTOR_; + } + + @Override + public Class getHostClass() { + return BarProp.class; + } + + @Override + public Class[] getDomClasses() { + return new Class[0]; + } + + @Override + public boolean isJsObject() { + return true; + } + + @Override + public String getExtendedClassName() { + return ""; + } + }; } diff --git a/src/main/java/org/htmlunit/javascript/host/Gamepad.java b/src/main/java/org/htmlunit/javascript/host/Gamepad.java index bdaa2b4ae3..0ab736c1fb 100644 --- a/src/main/java/org/htmlunit/javascript/host/Gamepad.java +++ b/src/main/java/org/htmlunit/javascript/host/Gamepad.java @@ -14,9 +14,11 @@ */ package org.htmlunit.javascript.host; +import org.htmlunit.corejs.javascript.ClassDescriptor; +import org.htmlunit.corejs.javascript.Undefined; import org.htmlunit.javascript.HtmlUnitScriptable; -import org.htmlunit.javascript.configuration.JsxClass; -import org.htmlunit.javascript.configuration.JsxConstructor; +import org.htmlunit.javascript.configuration.HtmlUnitClassDescriptor; +import org.htmlunit.javascript.configuration.SupportedBrowser; /** * A JavaScript object for {@code Gamepad}. @@ -24,14 +26,38 @@ * @author Ahmed Ashour * @author Ronald Brill */ -@JsxClass public class Gamepad extends HtmlUnitScriptable { - /** - * JavaScript constructor. - */ - @JsxConstructor - public void jsConstructor() { - // nothing to do - } + /** Descriptor for registering this class with the JavaScript engine. */ + public static final HtmlUnitClassDescriptor HTMLUNIT_DESCRIPTOR = new HtmlUnitClassDescriptor() { + + private static final ClassDescriptor DESCRIPTOR_ = new ClassDescriptor.Builder("Gamepad", 0, + (cx, f, callerObj, scope, thisObj, args) -> Undefined.instance) + .build(); + + @Override + public ClassDescriptor forBrowser(final SupportedBrowser browser) { + return DESCRIPTOR_; + } + + @Override + public Class getHostClass() { + return Gamepad.class; + } + + @Override + public Class[] getDomClasses() { + return new Class[0]; + } + + @Override + public boolean isJsObject() { + return true; + } + + @Override + public String getExtendedClassName() { + return ""; + } + }; } diff --git a/src/main/java/org/htmlunit/javascript/host/GamepadButton.java b/src/main/java/org/htmlunit/javascript/host/GamepadButton.java index 1e8dcd5a14..9faf6e78a7 100644 --- a/src/main/java/org/htmlunit/javascript/host/GamepadButton.java +++ b/src/main/java/org/htmlunit/javascript/host/GamepadButton.java @@ -14,9 +14,11 @@ */ package org.htmlunit.javascript.host; +import org.htmlunit.corejs.javascript.ClassDescriptor; +import org.htmlunit.corejs.javascript.Undefined; import org.htmlunit.javascript.HtmlUnitScriptable; -import org.htmlunit.javascript.configuration.JsxClass; -import org.htmlunit.javascript.configuration.JsxConstructor; +import org.htmlunit.javascript.configuration.HtmlUnitClassDescriptor; +import org.htmlunit.javascript.configuration.SupportedBrowser; /** * A JavaScript object for {@code GamepadButton}. @@ -24,14 +26,38 @@ * @author Ahmed Ashour * @author Ronald Brill */ -@JsxClass public class GamepadButton extends HtmlUnitScriptable { - /** - * JavaScript constructor. - */ - @JsxConstructor - public void jsConstructor() { - // nothing to do - } + /** Descriptor for registering this class with the JavaScript engine. */ + public static final HtmlUnitClassDescriptor HTMLUNIT_DESCRIPTOR = new HtmlUnitClassDescriptor() { + + private static final ClassDescriptor DESCRIPTOR_ = new ClassDescriptor.Builder("GamepadButton", 0, + (cx, f, callerObj, scope, thisObj, args) -> Undefined.instance) + .build(); + + @Override + public ClassDescriptor forBrowser(final SupportedBrowser browser) { + return DESCRIPTOR_; + } + + @Override + public Class getHostClass() { + return GamepadButton.class; + } + + @Override + public Class[] getDomClasses() { + return new Class[0]; + } + + @Override + public boolean isJsObject() { + return true; + } + + @Override + public String getExtendedClassName() { + return ""; + } + }; } diff --git a/src/main/java/org/htmlunit/javascript/host/dom/IdleDeadline.java b/src/main/java/org/htmlunit/javascript/host/dom/IdleDeadline.java index 62f3593294..f1fde54ceb 100644 --- a/src/main/java/org/htmlunit/javascript/host/dom/IdleDeadline.java +++ b/src/main/java/org/htmlunit/javascript/host/dom/IdleDeadline.java @@ -14,9 +14,11 @@ */ package org.htmlunit.javascript.host.dom; +import org.htmlunit.corejs.javascript.ClassDescriptor; +import org.htmlunit.corejs.javascript.Undefined; import org.htmlunit.javascript.HtmlUnitScriptable; -import org.htmlunit.javascript.configuration.JsxClass; -import org.htmlunit.javascript.configuration.JsxConstructor; +import org.htmlunit.javascript.configuration.HtmlUnitClassDescriptor; +import org.htmlunit.javascript.configuration.SupportedBrowser; /** * A JavaScript object for {@code IdleDeadline}. @@ -24,14 +26,38 @@ * @author Ahmed Ashour * @author Ronald Brill */ -@JsxClass public class IdleDeadline extends HtmlUnitScriptable { - /** - * JavaScript constructor. - */ - @JsxConstructor - public void jsConstructor() { - // nothing to do - } + /** Descriptor for registering this class with the JavaScript engine. */ + public static final HtmlUnitClassDescriptor HTMLUNIT_DESCRIPTOR = new HtmlUnitClassDescriptor() { + + private static final ClassDescriptor DESCRIPTOR_ = new ClassDescriptor.Builder("IdleDeadline", 0, + (cx, f, callerObj, scope, thisObj, args) -> Undefined.instance) + .build(); + + @Override + public ClassDescriptor forBrowser(final SupportedBrowser browser) { + return DESCRIPTOR_; + } + + @Override + public Class getHostClass() { + return IdleDeadline.class; + } + + @Override + public Class[] getDomClasses() { + return new Class[0]; + } + + @Override + public boolean isJsObject() { + return true; + } + + @Override + public String getExtendedClassName() { + return ""; + } + }; } diff --git a/src/main/java/org/htmlunit/javascript/host/geo/GeolocationCoordinates.java b/src/main/java/org/htmlunit/javascript/host/geo/GeolocationCoordinates.java index 3ac1bb5eb2..6c1a487caa 100644 --- a/src/main/java/org/htmlunit/javascript/host/geo/GeolocationCoordinates.java +++ b/src/main/java/org/htmlunit/javascript/host/geo/GeolocationCoordinates.java @@ -14,11 +14,12 @@ */ package org.htmlunit.javascript.host.geo; +import org.htmlunit.corejs.javascript.ClassDescriptor; +import org.htmlunit.corejs.javascript.ScriptableObject; import org.htmlunit.javascript.HtmlUnitScriptable; import org.htmlunit.javascript.JavaScriptEngine; -import org.htmlunit.javascript.configuration.JsxClass; -import org.htmlunit.javascript.configuration.JsxConstructor; -import org.htmlunit.javascript.configuration.JsxGetter; +import org.htmlunit.javascript.configuration.HtmlUnitClassDescriptor; +import org.htmlunit.javascript.configuration.SupportedBrowser; /** * A JavaScript object for GeolocationCoordinates. @@ -26,13 +27,62 @@ * @author Ahmed Ashour * @author Ronald Brill */ -@JsxClass public class GeolocationCoordinates extends HtmlUnitScriptable { private double latitude_; private double longitude_; private double accuracy_; + /** Descriptor for registering this class with the JavaScript engine. */ + public static final HtmlUnitClassDescriptor HTMLUNIT_DESCRIPTOR = new HtmlUnitClassDescriptor() { + + private static final ClassDescriptor DESCRIPTOR_ = new ClassDescriptor.Builder("GeolocationCoordinates", 0, + (cx, f, callerObj, scope, thisObj, args) -> { + throw JavaScriptEngine.typeErrorIllegalConstructor(); + }) + .withProp(ClassDescriptor.Destination.PROTO, "latitude", + (ScriptableObject.LambdaGetterFunction) thisObj -> + ((GeolocationCoordinates) thisObj).getLatitude(), + null, + ScriptableObject.DONTENUM | ScriptableObject.READONLY) + .withProp(ClassDescriptor.Destination.PROTO, "longitude", + (ScriptableObject.LambdaGetterFunction) thisObj -> + ((GeolocationCoordinates) thisObj).getLongitude(), + null, + ScriptableObject.DONTENUM | ScriptableObject.READONLY) + .withProp(ClassDescriptor.Destination.PROTO, "accuracy", + (ScriptableObject.LambdaGetterFunction) thisObj -> + ((GeolocationCoordinates) thisObj).getAccuracy(), + null, + ScriptableObject.DONTENUM | ScriptableObject.READONLY) + .build(); + + @Override + public ClassDescriptor forBrowser(final SupportedBrowser browser) { + return DESCRIPTOR_; + } + + @Override + public Class getHostClass() { + return GeolocationCoordinates.class; + } + + @Override + public Class[] getDomClasses() { + return new Class[0]; + } + + @Override + public boolean isJsObject() { + return true; + } + + @Override + public String getExtendedClassName() { + return ""; + } + }; + /** * Creates an instance. */ @@ -47,19 +97,10 @@ public GeolocationCoordinates() { accuracy_ = accuracy; } - /** - * Creates an instance. - */ - @JsxConstructor - public void jsConstructor() { - throw JavaScriptEngine.typeErrorIllegalConstructor(); - } - /** * Returns the latitude. * @return the latitude */ - @JsxGetter public double getLatitude() { return latitude_; } @@ -68,7 +109,6 @@ public double getLatitude() { * Returns the longitude. * @return the longitude */ - @JsxGetter public double getLongitude() { return longitude_; } @@ -77,7 +117,6 @@ public double getLongitude() { * Returns the accuracy. * @return the accuracy */ - @JsxGetter public double getAccuracy() { return accuracy_; } From 4d71bf08040a395072dfb8659e4bfb591cca2922 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 31 May 2026 15:32:21 +0000 Subject: [PATCH 2/2] Migrate SVGRect to lambda-based ClassDescriptor with getter/setter properties --- .../JavaScriptConfiguration.java | 3 +- .../htmlunit/javascript/host/svg/SVGRect.java | 84 ++++++++++++++----- 2 files changed, 65 insertions(+), 22 deletions(-) diff --git a/src/main/java/org/htmlunit/javascript/configuration/JavaScriptConfiguration.java b/src/main/java/org/htmlunit/javascript/configuration/JavaScriptConfiguration.java index 8ec8a10682..d84cf29bf6 100644 --- a/src/main/java/org/htmlunit/javascript/configuration/JavaScriptConfiguration.java +++ b/src/main/java/org/htmlunit/javascript/configuration/JavaScriptConfiguration.java @@ -571,7 +571,7 @@ public final class JavaScriptConfiguration extends AbstractJavaScriptConfigurati SVGAnimatedLengthList.class, SVGAnimatedNumber.class, SVGAnimatedNumberList.class, SVGAnimatedPreserveAspectRatio.class, SVGAnimatedRect.class, SVGAnimatedString.class, SVGAnimatedTransformList.class, SVGLength.class, SVGLengthList.class, SVGMatrix.class, SVGNumber.class, - SVGNumberList.class, SVGPoint.class, SVGPointList.class, SVGPreserveAspectRatio.class, SVGRect.class, + SVGNumberList.class, SVGPoint.class, SVGPointList.class, SVGPreserveAspectRatio.class, SVGStringList.class, SVGTransform.class, SVGTransformList.class, SVGUnitTypes.class, Selection.class, SpeechGrammar.class, SpeechGrammarList.class, SpeechSynthesisVoice.class, Storage.class, StorageManager.class, StyleMedia.class, StyleSheet.class, @@ -718,6 +718,7 @@ protected HtmlUnitClassDescriptor[] getDescriptors() { GamepadButton.HTMLUNIT_DESCRIPTOR, GeolocationCoordinates.HTMLUNIT_DESCRIPTOR, IdleDeadline.HTMLUNIT_DESCRIPTOR, + SVGRect.HTMLUNIT_DESCRIPTOR, }; } diff --git a/src/main/java/org/htmlunit/javascript/host/svg/SVGRect.java b/src/main/java/org/htmlunit/javascript/host/svg/SVGRect.java index 4f78310784..88f8e0f84a 100644 --- a/src/main/java/org/htmlunit/javascript/host/svg/SVGRect.java +++ b/src/main/java/org/htmlunit/javascript/host/svg/SVGRect.java @@ -14,11 +14,13 @@ */ package org.htmlunit.javascript.host.svg; +import org.htmlunit.corejs.javascript.ClassDescriptor; +import org.htmlunit.corejs.javascript.ScriptableObject; +import org.htmlunit.corejs.javascript.Undefined; import org.htmlunit.javascript.HtmlUnitScriptable; -import org.htmlunit.javascript.configuration.JsxClass; -import org.htmlunit.javascript.configuration.JsxConstructor; -import org.htmlunit.javascript.configuration.JsxGetter; -import org.htmlunit.javascript.configuration.JsxSetter; +import org.htmlunit.javascript.JavaScriptEngine; +import org.htmlunit.javascript.configuration.HtmlUnitClassDescriptor; +import org.htmlunit.javascript.configuration.SupportedBrowser; /** * A JavaScript object for {@code SVGRect}. @@ -26,27 +28,74 @@ * @author Ahmed Ashour * @author Ronald Brill */ -@JsxClass public class SVGRect extends HtmlUnitScriptable { + /** Descriptor for registering this class with the JavaScript engine. */ + public static final HtmlUnitClassDescriptor HTMLUNIT_DESCRIPTOR = new HtmlUnitClassDescriptor() { + + private static final ClassDescriptor DESCRIPTOR_ = new ClassDescriptor.Builder("SVGRect", 0, + (cx, f, callerObj, scope, thisObj, args) -> Undefined.instance) + .withProp(ClassDescriptor.Destination.PROTO, "x", + (ScriptableObject.LambdaGetterFunction) thisObj -> + ((SVGRect) thisObj).getX(), + (ScriptableObject.LambdaSetterFunction) (owner, value) -> + ((SVGRect) owner).setX(JavaScriptEngine.toNumber(value)), + ScriptableObject.DONTENUM) + .withProp(ClassDescriptor.Destination.PROTO, "y", + (ScriptableObject.LambdaGetterFunction) thisObj -> + ((SVGRect) thisObj).getY(), + (ScriptableObject.LambdaSetterFunction) (owner, value) -> + ((SVGRect) owner).setY(JavaScriptEngine.toNumber(value)), + ScriptableObject.DONTENUM) + .withProp(ClassDescriptor.Destination.PROTO, "width", + (ScriptableObject.LambdaGetterFunction) thisObj -> + ((SVGRect) thisObj).getWidth(), + (ScriptableObject.LambdaSetterFunction) (owner, value) -> + ((SVGRect) owner).setWidth(JavaScriptEngine.toNumber(value)), + ScriptableObject.DONTENUM) + .withProp(ClassDescriptor.Destination.PROTO, "height", + (ScriptableObject.LambdaGetterFunction) thisObj -> + ((SVGRect) thisObj).getHeight(), + (ScriptableObject.LambdaSetterFunction) (owner, value) -> + ((SVGRect) owner).setHeight(JavaScriptEngine.toNumber(value)), + ScriptableObject.DONTENUM) + .build(); + + @Override + public ClassDescriptor forBrowser(final SupportedBrowser browser) { + return DESCRIPTOR_; + } + + @Override + public Class getHostClass() { + return SVGRect.class; + } + + @Override + public Class[] getDomClasses() { + return new Class[0]; + } + + @Override + public boolean isJsObject() { + return true; + } + + @Override + public String getExtendedClassName() { + return ""; + } + }; + private double xValue_; private double yValue_; private double width_; private double height_; - /** - * JavaScript constructor. - */ - @JsxConstructor - public void jsConstructor() { - // nothing to do - } - /** * Gets x. * @return x */ - @JsxGetter public double getX() { return xValue_; } @@ -55,7 +104,6 @@ public double getX() { * Sets x. * @param x the x */ - @JsxSetter public void setX(final double x) { xValue_ = x; } @@ -64,7 +112,6 @@ public void setX(final double x) { * Gets y. * @return y */ - @JsxGetter public double getY() { return yValue_; } @@ -73,7 +120,6 @@ public double getY() { * Sets y. * @param y the y */ - @JsxSetter public void setY(final double y) { yValue_ = y; } @@ -82,7 +128,6 @@ public void setY(final double y) { * Gets width. * @return width */ - @JsxGetter public double getWidth() { return width_; } @@ -91,7 +136,6 @@ public double getWidth() { * Sets width. * @param width the width */ - @JsxSetter public void setWidth(final double width) { width_ = width; } @@ -100,7 +144,6 @@ public void setWidth(final double width) { * Gets height. * @return height */ - @JsxGetter public double getHeight() { return height_; } @@ -109,7 +152,6 @@ public double getHeight() { * Sets height. * @param height the height */ - @JsxSetter public void setHeight(final double height) { height_ = height; }