Skip to content

Commit 31263dc

Browse files
committed
enforce @JsxConstructor method
1 parent d0d36e6 commit 31263dc

File tree

5 files changed

+66
-12
lines changed

5 files changed

+66
-12
lines changed

src/main/java/org/htmlunit/javascript/JavaScriptEngine.java

Lines changed: 6 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -328,19 +328,13 @@ public static void configureScope(final HtmlUnitScriptable jsScope,
328328
continue;
329329
}
330330

331-
final Map.Entry<String, Member> jsConstructor = config.getJsConstructor();
332331
if (prototype != null && config.isJsObject()) {
333-
if (jsConstructor == null) {
334-
final ScriptableObject constructor = config.getHostClass().getDeclaredConstructor().newInstance();
335-
((HtmlUnitScriptable) constructor).setClassName(jsClassName);
336-
defineConstructor(jsScope, prototype, constructor);
337-
configureConstantsStaticPropertiesAndStaticFunctions(config, constructor);
338-
}
339-
else {
340-
final FunctionObject function = new RecursiveFunctionObject(jsConstructor.getKey(), jsConstructor.getValue(), jsScope, browserVersion);
341-
addAsConstructorAndAlias(function, jsScope, prototype, config);
342-
configureConstantsStaticPropertiesAndStaticFunctions(config, function);
343-
}
332+
final Map.Entry<String, Member> jsConstructor = config.getJsConstructor();
333+
334+
// we have an Architecture test to make sure this is never null (jsxClassesShouldHaveJsxConstructor)
335+
final FunctionObject function = new RecursiveFunctionObject(jsConstructor.getKey(), jsConstructor.getValue(), jsScope, browserVersion);
336+
addAsConstructorAndAlias(function, jsScope, prototype, config);
337+
configureConstantsStaticPropertiesAndStaticFunctions(config, function);
344338
}
345339
}
346340
}

src/main/java/org/htmlunit/javascript/host/arrays/Atomics.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
import org.htmlunit.javascript.HtmlUnitScriptable;
1818
import org.htmlunit.javascript.configuration.JsxClass;
19+
import org.htmlunit.javascript.configuration.JsxConstructor;
1920

2021
/**
2122
* A JavaScript object for {@code Atomics}.
@@ -24,4 +25,12 @@
2425
*/
2526
@JsxClass
2627
public class Atomics extends HtmlUnitScriptable {
28+
29+
/**
30+
* JavaScript constructor.
31+
*/
32+
@JsxConstructor
33+
public void jsConstructor() {
34+
// nothing to do
35+
}
2736
}

src/main/java/org/htmlunit/javascript/host/css/CSS.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
import org.htmlunit.corejs.javascript.Scriptable;
1818
import org.htmlunit.javascript.HtmlUnitScriptable;
1919
import org.htmlunit.javascript.configuration.JsxClass;
20+
import org.htmlunit.javascript.configuration.JsxConstructor;
2021
import org.htmlunit.javascript.configuration.JsxStaticFunction;
2122

2223
/**
@@ -28,6 +29,14 @@
2829
@JsxClass
2930
public class CSS extends HtmlUnitScriptable {
3031

32+
/**
33+
* JavaScript constructor.
34+
*/
35+
@JsxConstructor
36+
public void jsConstructor() {
37+
// nothing to do
38+
}
39+
3140
/**
3241
* {@inheritDoc}
3342
*/

src/main/java/org/htmlunit/javascript/proxyautoconfig/ProxyAutoConfig.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
import org.htmlunit.javascript.HtmlUnitScriptable;
2525
import org.htmlunit.javascript.JavaScriptEngine;
2626
import org.htmlunit.javascript.configuration.JsxClass;
27+
import org.htmlunit.javascript.configuration.JsxConstructor;
2728
import org.htmlunit.javascript.configuration.JsxFunction;
2829
import org.htmlunit.util.SubnetUtils;
2930

@@ -46,6 +47,14 @@ private ProxyAutoConfig() {
4647
super();
4748
}
4849

50+
/**
51+
* JavaScript constructor.
52+
*/
53+
@JsxConstructor
54+
public void jsConstructor() {
55+
// nothing to do
56+
}
57+
4958
/**
5059
* Returns true if there is no domain name in the hostname (no dots).
5160
* @param host the hostname from the URL (excluding port number).

src/test/java/org/htmlunit/archunit/ArchitectureTest.java

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -290,6 +290,39 @@ public boolean test(final JavaClass javaClass) {
290290
.orShould().haveRawReturnType("void")
291291
.orShould().haveRawReturnType(isAssignableToScriptable);
292292

293+
private static final ArchCondition<JavaClass> haveJsxConstructorMethod =
294+
new ArchCondition<JavaClass>("have at least one method annotated with @JsxConstructor") {
295+
@Override
296+
public void check(final JavaClass javaClass, final ConditionEvents events) {
297+
final boolean hasJsxConstructor = javaClass.getAllMethods().stream()
298+
.anyMatch(method -> method.isAnnotatedWith(JsxConstructor.class));
299+
300+
if (!hasJsxConstructor) {
301+
events.add(SimpleConditionEvent.violated(javaClass,
302+
String.format("Class %s does not contain any method annotated with @JsxConstructor",
303+
javaClass.getName())));
304+
}
305+
}
306+
};
307+
308+
private static final DescribedPredicate<JavaClass> haveJsxClassWithPropertyIsJSObjectTrue =
309+
new DescribedPredicate<JavaClass>("@JsxClass isJSObject == true") {
310+
@Override
311+
public boolean test(final JavaClass clazz) {
312+
return clazz.getAnnotationOfType(JsxClass.class).isJSObject();
313+
}
314+
};
315+
316+
/**
317+
* Every JsxClass needs an implementation of JsxConstructor.
318+
*/
319+
@ArchTest
320+
public static final ArchRule jsxClassesShouldHaveJsxConstructor = classes()
321+
.that().areAnnotatedWith(JsxClass.class)
322+
.and(haveJsxClassWithPropertyIsJSObjectTrue)
323+
.or().areAnnotatedWith(JsxClasses.class)
324+
.should(haveJsxConstructorMethod);
325+
293326
/**
294327
* JsxConstructor should not used for constructors.
295328
*/

0 commit comments

Comments
 (0)