Fix Java 17 compilation and test issues (#12353)

* Adds --add-opens to the surefire-maven-plugin config required for deserialization using Gson/XStream
* Upgrades plugin dependencies to JDK 17 compatible versions
* Replaces some reflection that no longer works on JDK 17
* Fixes issues when mocking Random
* Run Nashorn dependant tests only on JDK < 15

Signed-off-by: Wouter Born <github@maindrain.net>
This commit is contained in:
Wouter Born 2022-02-23 16:13:56 +01:00 committed by GitHub
parent 223c9f929b
commit c028deefbe
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 62 additions and 39 deletions

View File

@ -53,7 +53,6 @@ public final class CreateBridgeServlet extends AbstractRedirectionServlet {
private static final String DEFAULT_LOCALE = "en"; private static final String DEFAULT_LOCALE = "en";
private static final long ONLINE_WAIT_TIMEOUT_IN_MILLISECONDS = 5000;
private static final long DISCOVERY_COMPLETION_TIMEOUT_IN_MILLISECONDS = 5000; private static final long DISCOVERY_COMPLETION_TIMEOUT_IN_MILLISECONDS = 5000;
private static final long CHECK_INTERVAL_IN_MILLISECONDS = 100; private static final long CHECK_INTERVAL_IN_MILLISECONDS = 100;
@ -62,6 +61,8 @@ public final class CreateBridgeServlet extends AbstractRedirectionServlet {
private final Inbox inbox; private final Inbox inbox;
private final ThingRegistry thingRegistry; private final ThingRegistry thingRegistry;
private long onlineWaitTimeoutInMilliseconds = 5000;
/** /**
* Creates a new {@link CreateBridgeServlet}. * Creates a new {@link CreateBridgeServlet}.
* *
@ -73,6 +74,10 @@ public final class CreateBridgeServlet extends AbstractRedirectionServlet {
this.thingRegistry = thingRegistry; this.thingRegistry = thingRegistry;
} }
public void setOnlineWaitTimeoutInMilliseconds(long onlineWaitTimeoutInMilliseconds) {
this.onlineWaitTimeoutInMilliseconds = onlineWaitTimeoutInMilliseconds;
}
@Override @Override
protected String getRedirectionDestination(HttpServletRequest request) { protected String getRedirectionDestination(HttpServletRequest request) {
String bridgeUidString = request.getParameter(BRIDGE_UID_PARAMETER_NAME); String bridgeUidString = request.getParameter(BRIDGE_UID_PARAMETER_NAME);
@ -175,7 +180,7 @@ public final class CreateBridgeServlet extends AbstractRedirectionServlet {
private void waitForBridgeToComeOnline(Thing bridge) { private void waitForBridgeToComeOnline(Thing bridge) {
try { try {
waitForConditionWithTimeout(() -> bridge.getStatus() == ThingStatus.ONLINE, waitForConditionWithTimeout(() -> bridge.getStatus() == ThingStatus.ONLINE,
ONLINE_WAIT_TIMEOUT_IN_MILLISECONDS); onlineWaitTimeoutInMilliseconds);
waitForConditionWithTimeout(new DiscoveryResultCountDoesNotChangeCondition(), waitForConditionWithTimeout(new DiscoveryResultCountDoesNotChangeCondition(),
DISCOVERY_COMPLETION_TIMEOUT_IN_MILLISECONDS); DISCOVERY_COMPLETION_TIMEOUT_IN_MILLISECONDS);
} catch (InterruptedException e) { } catch (InterruptedException e) {

View File

@ -75,7 +75,7 @@ public class ExponentialBackoffWithJitterTest {
@Test @Test
public void whenTheNumberOfFailedAttemptsIsNegativeThenZeroIsAssumedInstead() { public void whenTheNumberOfFailedAttemptsIsNegativeThenZeroIsAssumedInstead() {
// given: // given:
Random random = mock(Random.class); Random random = mock(Random.class, withSettings().withoutAnnotations());
when(random.nextLong()).thenReturn(RETRY_INTERVAL); when(random.nextLong()).thenReturn(RETRY_INTERVAL);
ExponentialBackoffWithJitter backoffStrategy = new ExponentialBackoffWithJitter(MINIMUM_WAIT_TIME, ExponentialBackoffWithJitter backoffStrategy = new ExponentialBackoffWithJitter(MINIMUM_WAIT_TIME,
@ -91,7 +91,7 @@ public class ExponentialBackoffWithJitterTest {
@Test @Test
public void whenThereIsNoFailedAttemptThenTheMaximalResultIsMinimumWaitTimePlusRetryInterval() { public void whenThereIsNoFailedAttemptThenTheMaximalResultIsMinimumWaitTimePlusRetryInterval() {
// given: // given:
Random random = mock(Random.class); Random random = mock(Random.class, withSettings().withoutAnnotations());
when(random.nextLong()).thenReturn(RETRY_INTERVAL); when(random.nextLong()).thenReturn(RETRY_INTERVAL);
ExponentialBackoffWithJitter backoffStrategy = new ExponentialBackoffWithJitter(MINIMUM_WAIT_TIME, ExponentialBackoffWithJitter backoffStrategy = new ExponentialBackoffWithJitter(MINIMUM_WAIT_TIME,
@ -107,7 +107,7 @@ public class ExponentialBackoffWithJitterTest {
@Test @Test
public void whenThereIsOneFailedAttemptThenTheMaximalResultIsMinimumWaitTimePlusTwiceTheRetryInterval() { public void whenThereIsOneFailedAttemptThenTheMaximalResultIsMinimumWaitTimePlusTwiceTheRetryInterval() {
// given: // given:
Random random = mock(Random.class); Random random = mock(Random.class, withSettings().withoutAnnotations());
when(random.nextLong()).thenReturn(RETRY_INTERVAL * 2); when(random.nextLong()).thenReturn(RETRY_INTERVAL * 2);
ExponentialBackoffWithJitter backoffStrategy = new ExponentialBackoffWithJitter(MINIMUM_WAIT_TIME, ExponentialBackoffWithJitter backoffStrategy = new ExponentialBackoffWithJitter(MINIMUM_WAIT_TIME,
@ -123,7 +123,7 @@ public class ExponentialBackoffWithJitterTest {
@Test @Test
public void whenThereAreTwoFailedAttemptsThenTheMaximalResultIsMinimumWaitTimePlusFourTimesTheRetryInterval() { public void whenThereAreTwoFailedAttemptsThenTheMaximalResultIsMinimumWaitTimePlusFourTimesTheRetryInterval() {
// given: // given:
Random random = mock(Random.class); Random random = mock(Random.class, withSettings().withoutAnnotations());
when(random.nextLong()).thenReturn(RETRY_INTERVAL * 4); when(random.nextLong()).thenReturn(RETRY_INTERVAL * 4);
ExponentialBackoffWithJitter backoffStrategy = new ExponentialBackoffWithJitter(MINIMUM_WAIT_TIME, ExponentialBackoffWithJitter backoffStrategy = new ExponentialBackoffWithJitter(MINIMUM_WAIT_TIME,
@ -139,7 +139,7 @@ public class ExponentialBackoffWithJitterTest {
@Test @Test
public void whenThereAreTwoFailedAttemptsThenTheMinimalResultIsTheMinimumWaitTime() { public void whenThereAreTwoFailedAttemptsThenTheMinimalResultIsTheMinimumWaitTime() {
// given: // given:
Random random = mock(Random.class); Random random = mock(Random.class, withSettings().withoutAnnotations());
when(random.nextLong()).thenReturn(0L); when(random.nextLong()).thenReturn(0L);
ExponentialBackoffWithJitter backoffStrategy = new ExponentialBackoffWithJitter(MINIMUM_WAIT_TIME, ExponentialBackoffWithJitter backoffStrategy = new ExponentialBackoffWithJitter(MINIMUM_WAIT_TIME,
@ -155,7 +155,7 @@ public class ExponentialBackoffWithJitterTest {
@Test @Test
public void whenTheDrawnRandomValueIsNegativeThenItIsProjectedToAPositiveValue() { public void whenTheDrawnRandomValueIsNegativeThenItIsProjectedToAPositiveValue() {
// given: // given:
Random random = mock(Random.class); Random random = mock(Random.class, withSettings().withoutAnnotations());
when(random.nextLong()).thenReturn(-RETRY_INTERVAL * 4 - 1); when(random.nextLong()).thenReturn(-RETRY_INTERVAL * 4 - 1);
ExponentialBackoffWithJitter backoffStrategy = new ExponentialBackoffWithJitter(MINIMUM_WAIT_TIME, ExponentialBackoffWithJitter backoffStrategy = new ExponentialBackoffWithJitter(MINIMUM_WAIT_TIME,
@ -171,7 +171,7 @@ public class ExponentialBackoffWithJitterTest {
@Test @Test
public void whenTheResultWouldBeLargerThanTheMaximumThenItIsCappedToTheMaximum() { public void whenTheResultWouldBeLargerThanTheMaximumThenItIsCappedToTheMaximum() {
// given: // given:
Random random = mock(Random.class); Random random = mock(Random.class, withSettings().withoutAnnotations());
when(random.nextLong()).thenReturn(MAXIMUM_WAIT_TIME - ALTERNATIVE_MINIMUM_WAIT_TIME); when(random.nextLong()).thenReturn(MAXIMUM_WAIT_TIME - ALTERNATIVE_MINIMUM_WAIT_TIME);
ExponentialBackoffWithJitter backoffStrategy = new ExponentialBackoffWithJitter(ALTERNATIVE_MINIMUM_WAIT_TIME, ExponentialBackoffWithJitter backoffStrategy = new ExponentialBackoffWithJitter(ALTERNATIVE_MINIMUM_WAIT_TIME,
@ -187,7 +187,7 @@ public class ExponentialBackoffWithJitterTest {
@Test @Test
public void whenTheResultWouldBeLargerThanTheAlternativeMaximumThenItIsCappedToTheAlternativeMaximum() { public void whenTheResultWouldBeLargerThanTheAlternativeMaximumThenItIsCappedToTheAlternativeMaximum() {
// given: // given:
Random random = mock(Random.class); Random random = mock(Random.class, withSettings().withoutAnnotations());
when(random.nextLong()).thenReturn(ALTERNATIVE_MAXIMUM_WAIT_TIME - ALTERNATIVE_MINIMUM_WAIT_TIME); when(random.nextLong()).thenReturn(ALTERNATIVE_MAXIMUM_WAIT_TIME - ALTERNATIVE_MINIMUM_WAIT_TIME);
ExponentialBackoffWithJitter backoffStrategy = new ExponentialBackoffWithJitter(ALTERNATIVE_MINIMUM_WAIT_TIME, ExponentialBackoffWithJitter backoffStrategy = new ExponentialBackoffWithJitter(ALTERNATIVE_MINIMUM_WAIT_TIME,

View File

@ -112,6 +112,14 @@
</configuration> </configuration>
</execution> </execution>
</executions> </executions>
<dependencies>
<dependency>
<!-- Required for JDK 17 compatibility, see: https://github.com/swagger-api/swagger-codegen/issues/11253 -->
<groupId>com.github.jknack</groupId>
<artifactId>handlebars</artifactId>
<version>4.3.0</version>
</dependency>
</dependencies>
</plugin> </plugin>
</plugins> </plugins>
</build> </build>

View File

@ -46,6 +46,14 @@
</plugin> </plugin>
</plugins> </plugins>
</configuration> </configuration>
<dependencies>
<dependency>
<!-- Required for JDK 17 compatibility, see: https://github.com/highsource/maven-jaxb2-plugin/issues/207 -->
<groupId>org.glassfish.jaxb</groupId>
<artifactId>jaxb-runtime</artifactId>
<version>2.3.6</version>
</dependency>
</dependencies>
</plugin> </plugin>
</plugins> </plugins>
</build> </build>

View File

@ -89,7 +89,7 @@ public class ScheduleTests {
commonSetup.start(new ResourceConfig().registerInstances(subject)); commonSetup.start(new ResourceConfig().registerInstances(subject));
// Mock random -> always return int=10 or the highest possible int if bounded // Mock random -> always return int=10 or the highest possible int if bounded
Random random = mock(Random.class); Random random = mock(Random.class, withSettings().withoutAnnotations());
doReturn(10).when(random).nextInt(); doReturn(10).when(random).nextInt();
doAnswer(a -> { doAnswer(a -> {
Integer bound = a.getArgument(0); Integer bound = a.getArgument(0);

View File

@ -13,6 +13,7 @@
package org.openhab.transform.javascript.internal; package org.openhab.transform.javascript.internal;
import static org.junit.jupiter.api.Assertions.*; import static org.junit.jupiter.api.Assertions.*;
import static org.junit.jupiter.api.Assumptions.assumeTrue;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
@ -40,6 +41,8 @@ import org.osgi.framework.BundleContext;
@MockitoSettings(strictness = Strictness.WARN) @MockitoSettings(strictness = Strictness.WARN)
public class JavaScriptTransformationServiceTest { public class JavaScriptTransformationServiceTest {
private static final boolean NASHORN_AVAILABLE = isNashornAvailable();
private static final String BASE_FOLDER = "target"; private static final String BASE_FOLDER = "target";
private static final String SRC_FOLDER = "conf"; private static final String SRC_FOLDER = "conf";
private static final String CONFIG_FOLDER = BASE_FOLDER + File.separator + SRC_FOLDER; private static final String CONFIG_FOLDER = BASE_FOLDER + File.separator + SRC_FOLDER;
@ -54,8 +57,25 @@ public class JavaScriptTransformationServiceTest {
} }
}; };
/**
* Returns if the Nashorn JavaScript engine is available based on the Java specification version property.
* Nashorn has been removed from JDK 15 and onwards.
*
* @return {@code true} if Nashorn is available, {@code false} otherwise
*/
private static boolean isNashornAvailable() {
try {
String javaVersion = System.getProperty("java.specification.version");
return javaVersion == null ? false : Long.parseLong(javaVersion) < 15;
} catch (NumberFormatException e) {
return false;
}
}
@BeforeEach @BeforeEach
public void setUp() throws IOException { public void setUp() throws IOException {
assumeTrue(NASHORN_AVAILABLE);
JavaScriptEngineManager manager = new JavaScriptEngineManager(); JavaScriptEngineManager manager = new JavaScriptEngineManager();
processor = new TestableJavaScriptTransformationService(manager); processor = new TestableJavaScriptTransformationService(manager);
copyDirectory(SRC_FOLDER, CONFIG_FOLDER); copyDirectory(SRC_FOLDER, CONFIG_FOLDER);
@ -63,8 +83,11 @@ public class JavaScriptTransformationServiceTest {
@AfterEach @AfterEach
public void tearDown() throws IOException { public void tearDown() throws IOException {
try (Stream<Path> walk = Files.walk(Path.of(CONFIG_FOLDER))) { Path path = Path.of(CONFIG_FOLDER);
walk.sorted(Comparator.reverseOrder()).map(Path::toFile).forEach(File::delete); if (Files.exists(path)) {
try (Stream<Path> walk = Files.walk(path)) {
walk.sorted(Comparator.reverseOrder()).map(Path::toFile).forEach(File::delete);
}
} }
} }

View File

@ -27,7 +27,6 @@ import org.openhab.binding.mielecloud.internal.handler.MieleBridgeHandler;
import org.openhab.binding.mielecloud.internal.handler.MieleHandlerFactory; import org.openhab.binding.mielecloud.internal.handler.MieleHandlerFactory;
import org.openhab.binding.mielecloud.internal.util.AbstractConfigFlowTest; import org.openhab.binding.mielecloud.internal.util.AbstractConfigFlowTest;
import org.openhab.binding.mielecloud.internal.util.MieleCloudBindingIntegrationTestConstants; import org.openhab.binding.mielecloud.internal.util.MieleCloudBindingIntegrationTestConstants;
import org.openhab.binding.mielecloud.internal.util.ReflectionUtil;
import org.openhab.binding.mielecloud.internal.util.Website; import org.openhab.binding.mielecloud.internal.util.Website;
import org.openhab.binding.mielecloud.internal.util.WebsiteCrawler; import org.openhab.binding.mielecloud.internal.util.WebsiteCrawler;
import org.openhab.binding.mielecloud.internal.webservice.MieleWebservice; import org.openhab.binding.mielecloud.internal.webservice.MieleWebservice;
@ -124,7 +123,7 @@ public class ConfigFlowTest extends AbstractConfigFlowTest {
public void configFlowWaitTimeoutExpiresWhenBridgeDoesNotComeOnline() throws Exception { public void configFlowWaitTimeoutExpiresWhenBridgeDoesNotComeOnline() throws Exception {
// given: // given:
setUpAuthorizationHandler(); setUpAuthorizationHandler();
ReflectionUtil.setPrivateStaticFinal(CreateBridgeServlet.class, "ONLINE_WAIT_TIMEOUT_IN_MILLISECONDS", 0); getCreateBridgeServlet().setOnlineWaitTimeoutInMilliseconds(0);
// when: // when:
configureBridgeWithConfigFlow(); configureBridgeWithConfigFlow();

View File

@ -15,7 +15,6 @@ package org.openhab.binding.mielecloud.internal.util;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException; import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import org.eclipse.jdt.annotation.NonNullByDefault; import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable; import org.eclipse.jdt.annotation.Nullable;
@ -80,29 +79,6 @@ public final class ReflectionUtil {
field.set(object, value); field.set(object, value);
} }
/**
* Sets an attribute declared as {@code private static final}.
*
* @param clazz The class owning the static attribute.
* @param fieldName The name of the attribute.
* @param value The new value.
* @throws NoSuchFieldException if no field with the given name exists.
* @throws SecurityException if the operation is not allowed.
* @throws IllegalArgumentException if one of the passed parameters is invalid.
* @throws IllegalAccessException if the field is enforcing Java language access control and is inaccessible.
*/
public static void setPrivateStaticFinal(Class<?> clazz, String fieldName, @Nullable Object value)
throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException {
Field field = clazz.getDeclaredField(fieldName);
field.setAccessible(true);
Field modifiersField = Field.class.getDeclaredField("modifiers");
modifiersField.setAccessible(true);
modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL);
field.set(null, value);
}
/** /**
* Invokes a private method on an object. * Invokes a private method on an object.
* *

View File

@ -385,6 +385,10 @@ Import-Package: \\
<artifactId>maven-surefire-plugin</artifactId> <artifactId>maven-surefire-plugin</artifactId>
<version>3.0.0-M5</version> <version>3.0.0-M5</version>
<configuration> <configuration>
<argLine>
--add-opens java.base/java.lang=ALL-UNNAMED
--add-opens java.base/java.util=ALL-UNNAMED
</argLine>
<systemPropertyVariables> <systemPropertyVariables>
<junit.jupiter.execution.timeout.default>15 m</junit.jupiter.execution.timeout.default> <junit.jupiter.execution.timeout.default>15 m</junit.jupiter.execution.timeout.default>
</systemPropertyVariables> </systemPropertyVariables>