re-formating with spotlessApply

This commit is contained in:
nabacg 2024-08-22 16:48:51 +01:00 коммит произвёл Greg Brail
Родитель 1bfad4824b
Коммит a736276482
4 изменённых файлов: 244 добавлений и 186 удалений

Просмотреть файл

@ -123,17 +123,21 @@ public class LambdaConstructor extends LambdaFunction {
proto.defineProperty(key, value, attributes);
}
public void definePrototypeProperty(String name, java.util.function.Function<Scriptable, Object> getter, int attributes) {
public void definePrototypeProperty(
String name, java.util.function.Function<Scriptable, Object> getter, int attributes) {
ScriptableObject proto = getPrototypeScriptable();
proto.defineProperty(name, getter, null, attributes);
}
public void definePrototypeProperty(String name, Function<Scriptable, Object> getter, BiConsumer<Scriptable, Object> setter, int attributes) {
public void definePrototypeProperty(
String name,
Function<Scriptable, Object> getter,
BiConsumer<Scriptable, Object> setter,
int attributes) {
ScriptableObject proto = getPrototypeScriptable();
proto.defineProperty(name, getter, setter, attributes);
}
/**
* Define a function property directly on the constructor that is implemented under the covers
* by a LambdaFunction.

Просмотреть файл

@ -1,22 +1,23 @@
package org.mozilla.javascript;
import java.util.IdentityHashMap;
import java.util.function.BiConsumer;
import java.util.function.Function;
/**
* A specialized property accessor using lambda functions, similar to {@link LambdaSlot},
* but allows defining properties with getter and setter lambdas that require access to the owner object ('this').
* This enables the implementation of properties that can access instance fields of the owner.
* A specialized property accessor using lambda functions, similar to {@link LambdaSlot}, but allows
* defining properties with getter and setter lambdas that require access to the owner object
* ('this'). This enables the implementation of properties that can access instance fields of the
* owner.
*
* Unlike {@link LambdaSlot}, Lambda functions used to define getter and setter logic require the owner's
* `Scriptable` object as one of the parameters.
* This is particularly useful for implementing properties that behave like standard JavaScript properties,
* but are implemented with native functionality without the need for reflection.
* <p>Unlike {@link LambdaSlot}, Lambda functions used to define getter and setter logic require the
* owner's `Scriptable` object as one of the parameters. This is particularly useful for
* implementing properties that behave like standard JavaScript properties, but are implemented with
* native functionality without the need for reflection.
*/
public class OwnerAwareLambdaSlot extends Slot {
private transient Function<Scriptable, Object> getter;
private transient BiConsumer<Scriptable, Object> setter;
OwnerAwareLambdaSlot(Object name, int index) {
super(name, index, 0);
}
@ -30,23 +31,32 @@ public class OwnerAwareLambdaSlot extends Slot {
return false;
}
@Override
ScriptableObject getPropertyDescriptor(Context cx, Scriptable scope) {
ScriptableObject desc = (ScriptableObject) cx.newObject(scope);
if (getter != null) {
desc.defineProperty("get",
new LambdaFunction(scope, "get " + super.name, 0, (cx1, scope1, thisObj, args) ->
getter.apply(thisObj)), ScriptableObject.EMPTY);
desc.defineProperty(
"get",
new LambdaFunction(
scope,
"get " + super.name,
0,
(cx1, scope1, thisObj, args) -> getter.apply(thisObj)),
ScriptableObject.EMPTY);
}
if (setter != null) {
desc.defineProperty("set",
new LambdaFunction(scope, "set " + super.name, 1, (cx1, scope1, thisObj, args) ->
{
desc.defineProperty(
"set",
new LambdaFunction(
scope,
"set " + super.name,
1,
(cx1, scope1, thisObj, args) -> {
setter.accept(thisObj, args[0]);
return Undefined.instance;
}), ScriptableObject.EMPTY);
}),
ScriptableObject.EMPTY);
}
desc.setCommonDescriptorProperties(getAttributes(), false);
return desc;

Просмотреть файл

@ -1692,28 +1692,34 @@ public abstract class ScriptableObject
}
/**
* Define a property on this object that is implemented using lambda functions accepting Scriptable `this` object
* as first parameter. Unlike with `defineProperty(String name, Supplier<Object> getter, Consumer<Object> setter, int attributes)`
* where getter and setter need to have access to target object instance, this allows for defining properties on
* LambdaConstructor prototype providing getter and setter logic with java instance methods.
* If a property with the same name already exists, then it will be replaced. This property will appear to the
* JavaScript user exactly like any other property -- unlike Function properties and those based
* on reflection, the property descriptor will only reflect the value as defined by this
* function.
* Define a property on this object that is implemented using lambda functions accepting
* Scriptable `this` object as first parameter. Unlike with `defineProperty(String name,
* Supplier<Object> getter, Consumer<Object> setter, int attributes)` where getter and setter
* need to have access to target object instance, this allows for defining properties on
* LambdaConstructor prototype providing getter and setter logic with java instance methods. If
* a property with the same name already exists, then it will be replaced. This property will
* appear to the JavaScript user exactly like any other property -- unlike Function properties
* and those based on reflection, the property descriptor will only reflect the value as defined
* by this function.
*
* @param name the name of the property
* @param getter a function that given Scriptable `this` returns the value of the property. If null, throws typeError
* @param setter a function that Scriptable `this` and a value sets the value of the property, by calling appropriate
* method on `this`. If null, then the value will be
* set directly and may not be retrieved by the getter.
* @param getter a function that given Scriptable `this` returns the value of the property. If
* null, throws typeError
* @param setter a function that Scriptable `this` and a value sets the value of the property,
* by calling appropriate method on `this`. If null, then the value will be set directly and
* may not be retrieved by the getter.
* @param attributes the attributes to set on the property
*/
public void defineProperty(
String name, java.util.function.Function<Scriptable, Object> getter, BiConsumer<Scriptable, Object> setter, int attributes) {
String name,
java.util.function.Function<Scriptable, Object> getter,
BiConsumer<Scriptable, Object> setter,
int attributes) {
if (getter == null && setter == null)
throw ScriptRuntime.typeError("at least one of {getter, setter} is required");
OwnerAwareLambdaSlot slot = slotMap.compute(name, 0, ScriptableObject::ensureOwnerAwareLambdaSlot);
OwnerAwareLambdaSlot slot =
slotMap.compute(name, 0, ScriptableObject::ensureOwnerAwareLambdaSlot);
slot.setAttributes(attributes);
slot.setGetter(getter);
@ -2725,7 +2731,8 @@ public abstract class ScriptableObject
}
}
private static OwnerAwareLambdaSlot ensureOwnerAwareLambdaSlot(Object name, int index, Slot existing) {
private static OwnerAwareLambdaSlot ensureOwnerAwareLambdaSlot(
Object name, int index, Slot existing) {
if (existing == null) {
return new OwnerAwareLambdaSlot(name, index);
} else if (existing instanceof OwnerAwareLambdaSlot) {

Просмотреть файл

@ -1,20 +1,19 @@
package org.mozilla.javascript.tests;
import static org.junit.Assert.*;
import static org.mozilla.javascript.ScriptableObject.DONTENUM;
import static org.mozilla.javascript.tests.OwnerAwareLambdaSlotTest.StatusHolder.self;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.mozilla.javascript.Context;
import org.mozilla.javascript.ContextFactory;
import org.mozilla.javascript.EcmaError;
import org.mozilla.javascript.LambdaConstructor;
import org.mozilla.javascript.Scriptable;
import org.mozilla.javascript.ScriptableObject;
import org.mozilla.javascript.Undefined;
import static org.junit.Assert.*;
import static org.mozilla.javascript.ScriptableObject.DONTENUM;
import static org.mozilla.javascript.tests.OwnerAwareLambdaSlotTest.StatusHolder.self;
public class OwnerAwareLambdaSlotTest {
private Context cx;
private ScriptableObject scope;
@ -30,45 +29,44 @@ public class OwnerAwareLambdaSlotTest {
Context.exit();
}
@Test
public void testGetterProperty() {
StatusHolder
.init(scope)
.definePrototypeProperty("status",
StatusHolder.init(scope)
.definePrototypeProperty(
"status",
(thisObj) -> self(thisObj).getStatus(),
(thisObj, value) ->
self(thisObj).setStatus(value),
(thisObj, value) -> self(thisObj).setStatus(value),
DONTENUM);
Object getterResult = cx.evaluateString(scope, "s = new StatusHolder('InProgress'); s.status", "source", 1, null);
Object getterResult =
cx.evaluateString(
scope, "s = new StatusHolder('InProgress'); s.status", "source", 1, null);
assertEquals("InProgress", getterResult);
}
@Test
public void testThrowIfNeitherGetterOrSetterAreDefined() {
var error = assertThrows(EcmaError.class, () ->
StatusHolder
.init(scope)
.definePrototypeProperty("status",
null,
null,
DONTENUM));
var error =
assertThrows(
EcmaError.class,
() ->
StatusHolder.init(scope)
.definePrototypeProperty("status", null, null, DONTENUM));
assertTrue(error.toString().contains("at least one of {getter, setter} is required"));
}
@Test
public void testCanUpdateValueUsingSetter() {
StatusHolder
.init(scope)
.definePrototypeProperty("status",
StatusHolder.init(scope)
.definePrototypeProperty(
"status",
(thisObj) -> self(thisObj).getStatus(),
(thisObj, value) ->
self(thisObj).setStatus(value),
(thisObj, value) -> self(thisObj).setStatus(value),
DONTENUM);
Object getterResult = cx.evaluateString(scope, "s = new StatusHolder('InProgress'); s.status", "source", 1, null);
Object getterResult =
cx.evaluateString(
scope, "s = new StatusHolder('InProgress'); s.status", "source", 1, null);
assertEquals("InProgress", getterResult);
Object setResult = cx.evaluateString(scope, "s.status = 'DONE';", "source", 1, null);
@ -79,45 +77,58 @@ public class OwnerAwareLambdaSlotTest {
@Test
public void testOnlyGetterCanBeAccessed() {
StatusHolder
.init(scope)
.definePrototypeProperty("status", (thisObj) -> self(thisObj).getStatus(), DONTENUM);
StatusHolder.init(scope)
.definePrototypeProperty(
"status", (thisObj) -> self(thisObj).getStatus(), DONTENUM);
Object getterResult = cx.evaluateString(scope, "new StatusHolder('OK').status", "source", 1, null);
Object getterResult =
cx.evaluateString(scope, "new StatusHolder('OK').status", "source", 1, null);
assertEquals("OK", getterResult);
Object hiddenFieldResult = cx.evaluateString(scope, "new StatusHolder('OK').hiddenStatus", "source", 1, null);
assertEquals("fields not explicitly defined as properties should return undefined", Undefined.instance, hiddenFieldResult);
Object hiddenFieldResult =
cx.evaluateString(scope, "new StatusHolder('OK').hiddenStatus", "source", 1, null);
assertEquals(
"fields not explicitly defined as properties should return undefined",
Undefined.instance,
hiddenFieldResult);
}
@Test
public void testWhenNoSetterDefined_InStrictMode_WillThrowException() {
StatusHolder
.init(scope)
.definePrototypeProperty("status",
(thisObj) -> self(thisObj).getStatus(),
DONTENUM);
Object getterResult = cx.evaluateString(scope, "s = new StatusHolder('Constant'); s.status", "source", 1, null);
StatusHolder.init(scope)
.definePrototypeProperty(
"status", (thisObj) -> self(thisObj).getStatus(), DONTENUM);
Object getterResult =
cx.evaluateString(
scope, "s = new StatusHolder('Constant'); s.status", "source", 1, null);
assertEquals("Constant", getterResult);
var error = assertThrows(EcmaError.class, () ->
cx.evaluateString(scope,
"\"use strict\"; s.status = 'DONE'; s.status", "source", 1, null));
var error =
assertThrows(
EcmaError.class,
() ->
cx.evaluateString(
scope,
"\"use strict\"; s.status = 'DONE'; s.status",
"source",
1,
null));
assertTrue(error.toString().contains("Cannot modify readonly property: status."));
}
@Test
public void testWhenNoSetterDefined_InNormalMode_NoErrorButValueIsNotChanged() {
StatusHolder
.init(scope)
.definePrototypeProperty("status",
(thisObj) -> self(thisObj).getStatus(),
DONTENUM);
StatusHolder.init(scope)
.definePrototypeProperty(
"status", (thisObj) -> self(thisObj).getStatus(), DONTENUM);
Object getterResult = cx.evaluateString(scope, "s = new StatusHolder('Constant'); s.status", "source", 1, null);
Object getterResult =
cx.evaluateString(
scope, "s = new StatusHolder('Constant'); s.status", "source", 1, null);
assertEquals("Constant", getterResult);
Object setResult = cx.evaluateString(scope, "s.status = 'DONE'; s.status", "source", 1, null);
Object setResult =
cx.evaluateString(scope, "s.status = 'DONE'; s.status", "source", 1, null);
assertEquals("status won't be changed", "Constant", setResult);
Object shObj = cx.evaluateString(scope, "s", "source", 1, null);
@ -127,18 +138,16 @@ public class OwnerAwareLambdaSlotTest {
@Test
public void testSetterOnly_WillModifyUnderlyingValue() {
StatusHolder
.init(scope)
.definePrototypeProperty("status",
StatusHolder.init(scope)
.definePrototypeProperty(
"status",
null,
(thisObj, value) ->
self(thisObj).setStatus(value),
(thisObj, value) -> self(thisObj).setStatus(value),
DONTENUM);
cx.evaluateString(scope, "s = new StatusHolder('Constant')", "source", 1, null);
cx.evaluateString(scope, "s.status = 'DONE'; s.status", "source", 1, null);
Object newStatus = cx.evaluateString(scope, "s.status", "source", 1, null);
assertEquals(Undefined.instance, newStatus);
Object shObj = cx.evaluateString(scope, "s", "source", 1, null);
@ -146,147 +155,175 @@ public class OwnerAwareLambdaSlotTest {
assertEquals("NewStatus: DONE", statusHolder.getStatus());
}
// using getOwnPropertyDescriptor to access property
@Test
public void testGetterUsing_getOwnPropertyDescriptor() {
StatusHolder
.init(scope)
.definePrototypeProperty("status",
(thisObj) -> self(thisObj).getStatus(), DONTENUM);
StatusHolder.init(scope)
.definePrototypeProperty(
"status", (thisObj) -> self(thisObj).getStatus(), DONTENUM);
Object result = cx.evaluateString(scope, "s = new StatusHolder('InProgress');" +
"f = Object.getOwnPropertyDescriptor(Object.getPrototypeOf(s), 'status');" +
"f.get.call(s)",
"source", 1, null);
Object result =
cx.evaluateString(
scope,
"s = new StatusHolder('InProgress');"
+ "f = Object.getOwnPropertyDescriptor(Object.getPrototypeOf(s), 'status');"
+ "f.get.call(s)",
"source",
1,
null);
assertEquals("InProgress", result);
}
@Test
public void testSetterOnlyUsing_getOwnPropertyDescriptor() {
StatusHolder
.init(scope)
.definePrototypeProperty("status",
StatusHolder.init(scope)
.definePrototypeProperty(
"status",
null,
(thisObj, value) ->
self(thisObj).setStatus(value), DONTENUM);
(thisObj, value) -> self(thisObj).setStatus(value),
DONTENUM);
Object shObj = cx.evaluateString(scope,
"s = new StatusHolder('InProgress');" +
"f = Object.getOwnPropertyDescriptor(Object.getPrototypeOf(s), 'status');" +
"f.set.call(s, 'DONE');" +
"s",
"source", 1, null);
Object shObj =
cx.evaluateString(
scope,
"s = new StatusHolder('InProgress');"
+ "f = Object.getOwnPropertyDescriptor(Object.getPrototypeOf(s), 'status');"
+ "f.set.call(s, 'DONE');"
+ "s",
"source",
1,
null);
var statusHolder = (StatusHolder) shObj;
assertEquals("NewStatus: DONE", statusHolder.getStatus());
}
@Test
public void testSetValueUsing_getOwnPropertyDescriptor() {
StatusHolder
.init(scope)
.definePrototypeProperty("status",
StatusHolder.init(scope)
.definePrototypeProperty(
"status",
(thisObj) -> self(thisObj).getStatus(),
(thisObj, value) ->
self(thisObj).setStatus(value), DONTENUM);
(thisObj, value) -> self(thisObj).setStatus(value),
DONTENUM);
Object result = cx.evaluateString(scope,
"s = new StatusHolder('InProgress');" +
"f = Object.getOwnPropertyDescriptor(Object.getPrototypeOf(s), 'status');" +
"f.set.call(s, 'DONE');" +
"s.status",
"source", 1, null);
Object result =
cx.evaluateString(
scope,
"s = new StatusHolder('InProgress');"
+ "f = Object.getOwnPropertyDescriptor(Object.getPrototypeOf(s), 'status');"
+ "f.set.call(s, 'DONE');"
+ "s.status",
"source",
1,
null);
assertEquals("Status with prefix", "NewStatus: DONE", result);
}
@Test
public void testSetterOnlyUsing_getOwnPropertyDescriptor_ErrorOnGet() {
StatusHolder
.init(scope)
.definePrototypeProperty("status",
StatusHolder.init(scope)
.definePrototypeProperty(
"status",
null,
(thisObj, value) ->
self(thisObj).setStatus(value), DONTENUM);
(thisObj, value) -> self(thisObj).setStatus(value),
DONTENUM);
var error = assertThrows(EcmaError.class, () ->
cx.evaluateString(scope,
"var s = new StatusHolder('InProgress');" +
"var f = Object.getOwnPropertyDescriptor(Object.getPrototypeOf(s), 'status');" +
"f.get.call(s)",
"source", 1, null));
var error =
assertThrows(
EcmaError.class,
() ->
cx.evaluateString(
scope,
"var s = new StatusHolder('InProgress');"
+ "var f = Object.getOwnPropertyDescriptor(Object.getPrototypeOf(s), 'status');"
+ "f.get.call(s)",
"source",
1,
null));
assertTrue(error.toString().contains("Cannot call method \"call\" of undefined"));
}
@Test
public void testSetterOnlyUsing_getOwnPropertyDescriptor_InStrictMode_ErrorOnGet() {
StatusHolder
.init(scope)
.definePrototypeProperty("status",
StatusHolder.init(scope)
.definePrototypeProperty(
"status",
null,
(thisObj, value) ->
self(thisObj).setStatus(value), DONTENUM);
(thisObj, value) -> self(thisObj).setStatus(value),
DONTENUM);
var error = assertThrows(EcmaError.class, () ->
cx.evaluateString(scope,
"\"use strict\";"+
"var s = new StatusHolder('InProgress');" +
"var f = Object.getOwnPropertyDescriptor(Object.getPrototypeOf(s), 'status');" +
"f.get.call(s)",
"source", 1, null));
var error =
assertThrows(
EcmaError.class,
() ->
cx.evaluateString(
scope,
"\"use strict\";"
+ "var s = new StatusHolder('InProgress');"
+ "var f = Object.getOwnPropertyDescriptor(Object.getPrototypeOf(s), 'status');"
+ "f.get.call(s)",
"source",
1,
null));
assertTrue(error.toString().contains("Cannot call method \"call\" of undefined"));
}
@Test
public void testGetterOnlyUsing_getOwnPropertyDescriptor_ErrorOnSet() {
StatusHolder
.init(scope)
.definePrototypeProperty("status",
(thisObj) -> self(thisObj).getStatus(), DONTENUM);
StatusHolder.init(scope)
.definePrototypeProperty(
"status", (thisObj) -> self(thisObj).getStatus(), DONTENUM);
var error = assertThrows(EcmaError.class, () ->
cx.evaluateString(scope,
"var s = new StatusHolder('InProgress');" +
"var f = Object.getOwnPropertyDescriptor(Object.getPrototypeOf(s), 'status');" +
"f.set.call(s, 'DONE');" +
"s.status",
"source", 1, null));
var error =
assertThrows(
EcmaError.class,
() ->
cx.evaluateString(
scope,
"var s = new StatusHolder('InProgress');"
+ "var f = Object.getOwnPropertyDescriptor(Object.getPrototypeOf(s), 'status');"
+ "f.set.call(s, 'DONE');"
+ "s.status",
"source",
1,
null));
assertTrue(error.toString().contains("Cannot call method \"call\" of undefined"));
}
@Test
public void testGetterOnlyUsing_getOwnPropertyDescriptor_InStrictMode_ErrorOnSet() {
StatusHolder
.init(scope)
.definePrototypeProperty("status",
(thisObj) -> self(thisObj).getStatus(), DONTENUM);
StatusHolder.init(scope)
.definePrototypeProperty(
"status", (thisObj) -> self(thisObj).getStatus(), DONTENUM);
var error = assertThrows(EcmaError.class, () ->
cx.evaluateString(scope,
"\"use strict\";" +
"var s = new StatusHolder('InProgress');" +
"var f = Object.getOwnPropertyDescriptor(Object.getPrototypeOf(s), 'status');" +
"f.set.call(s, 'DONE');" +
"s.status",
"source", 1, null));
var error =
assertThrows(
EcmaError.class,
() ->
cx.evaluateString(
scope,
"\"use strict\";"
+ "var s = new StatusHolder('InProgress');"
+ "var f = Object.getOwnPropertyDescriptor(Object.getPrototypeOf(s), 'status');"
+ "f.set.call(s, 'DONE');"
+ "s.status",
"source",
1,
null));
assertTrue(error.toString().contains("Cannot call method \"call\" of undefined"));
}
static class StatusHolder extends ScriptableObject {
private String status;
private final String hiddenStatus;
static LambdaConstructor init(Scriptable scope) {
LambdaConstructor constructor = new LambdaConstructor(scope, "StatusHolder", 1,
LambdaConstructor constructor =
new LambdaConstructor(
scope,
"StatusHolder",
1,
LambdaConstructor.CONSTRUCTOR_NEW,
(cx, scope1, args) -> new StatusHolder((String) args[0]));