Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow SDK to build on JDK 17 #3037

Merged
merged 3 commits into from
Feb 17, 2022
Merged

Allow SDK to build on JDK 17 #3037

merged 3 commits into from
Feb 17, 2022

Conversation

millems
Copy link
Contributor

@millems millems commented Feb 16, 2022

The following changes were required:

  1. Update environment variable mocking approach to no longer rely on reflection. Instead, all environment variable reading in the SDK (via SystemSetttings) supports value overrides via a testing backdoor added to SystemSettingsUtils.
  2. Update to Mockito 4.x from 1.x.
  3. Do not rely on reflection for comparing Instants in protocol-test-core
  4. Run tests with -XX:+AllowRedefinitionToAddDeleteMethods enabled, because blockhound requires it for Java 13+: OpenJDK 13 requires -XX:+AllowRedefinitionToAddDeleteMethods flag reactor/BlockHound#33

@millems millems requested a review from a team as a code owner February 16, 2022 18:20
Comment on lines +348 to +360
<property name="message" value="NEVER use System.getenv or System.getProperty. Create and use a
SystemSetting, instead."/>
<property name="ignoreComments" value="true"/>
</module>

<module name="Regexp">
<property name="format" value="SystemSetting\s*(\.|::)\s*getStringValueFromEnvironmentVariable"/>
<property name="illegalPattern" value="true"/>
<property name="message" value="Are you being naughty and not creating a SystemSetting? Don't you know that
your customers want both system properties AND environment variables? Are you REALLY sure you want to use
this and not support a system property?"/>
<property name="ignoreComments" value="true"/>
</module>
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note for reviewers: This was modified to really push people to use SystemSetting, because that's the only mechanism that supports environment variable mocking, now. We expect everyone to create new SystemSettings to support both properties and environment variables. If they really want to break that, then they can use the static SystemSetting.getStringValueFromEnvironmentVariable (long to be annoying to write), and they still have to add a checkstyle suppression to do it.

@@ -39,7 +39,7 @@ public static EnvironmentVariableCredentialsProvider create() {
protected Optional<String> loadSetting(SystemSetting setting) {
// CHECKSTYLE:OFF - Customers should be able to specify a credentials provider that only looks at the environment
// variables, but not the system properties. For that reason, we're only checking the environment variable here.
return Optional.ofNullable(System.getenv(setting.environmentVariable()));
return SystemSetting.getStringValueFromEnvironmentVariable(setting.environmentVariable());
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note for reviewer: Non-Mockito change. This uses SystemSetting to support mocking.

Comment on lines +69 to +75
/**
* Access the underlying delegate stream, for testing purposes.
*/
@SdkTestInternalApi
public InputStream delegate() {
return in;
}
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note to reviewer: Our existing tests relied on reflection to access 'in', which does not work in JDK 17. Now, we expose it via a test API. This should be okay, since this is a protected (not public) API.

Comment on lines +71 to +75
connectionInterceptor = safeFunction(connection -> new DelegateHttpURLConnection(connection) {
@Override
public int getResponseCode() {
throw new NullPointerException();
}
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note to reviewer: Mockito can no longer spy on classes loaded by the bootstrap class loader in JDK 17, so we had to do the method overriding manually.

Comment on lines -82 to -87
@Test
public void InstantAsStringAttributeConverterNotAcceptOffsetTimeTest() {
assertFails(() -> transformTo(CONVERTER, EnhancedAttributeValue.fromString("1988-05-21T00:12:00+01:00")
.toAttributeValue()));
}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note to reviewer: JDK 17 now supports parsing offset times. There shouldn't be a problem supporting this now, so I removed the assertion that we do not support it.

Comment on lines +122 to +127
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcpkix-jdk15on</artifactId>
<version>1.70</version>
<scope>compile</scope>
</dependency>
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note to reviewer: Netty uses JDK internals to generate self-signed certs for our netty services we spin up for testing purposes. This no longer works on JDK 17, because those classes aren't exposed. We add this (test, since it's a module that's only used for testing) dependency on bouncycastle, which netty will automatically use instead of the JDK classes.

@@ -62,7 +71,11 @@ private void assertFieldEquals(Field field, Object actual, Object expectedResult
assertTrue(IOUtils.contentEquals((InputStream) field.get(expectedResult),
(InputStream) field.get(actual)));
} else {
assertReflectionEquals(field.get(expectedResult), field.get(actual));
Difference difference = CustomComparatorFactory.getComparator()
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note to reviewer: this fixes an issue where the comparator is using reflection to compare instants (which fails on JDK 17), because our comparator library is old enough that it doesn't support Instant types. (It hasn't been updated since 2017).

…loading via SystemSettings.

This fixes an issue where the existing environment variable helpers did not work on Java 17, because it relied on reflectivly modifying the environment variable map directly.
@sonarcloud
Copy link

sonarcloud bot commented Feb 16, 2022

SonarCloud Quality Gate failed.    Quality Gate failed

Bug A 0 Bugs
Vulnerability A 0 Vulnerabilities
Security Hotspot A 0 Security Hotspots
Code Smell A 2 Code Smells

62.3% 62.3% Coverage
0.0% 0.0% Duplication

@millems millems enabled auto-merge (squash) February 16, 2022 23:19
@@ -108,7 +108,7 @@ private Boolean parseBooleanProperty(String propertyKey, String property) {
* Retrieve an unmodifiable view of all of the properties currently in this profile.
*/
public Map<String, String> properties() {
return properties;
return Collections.unmodifiableMap(properties);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we still require wrapping the input list as unmodifiableMap in builder line number 193 ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch! I didn't see that (and neither did spotbugs).

pom.xml Show resolved Hide resolved
private static class InstantComparator implements Comparator {
@Override
public boolean canCompare(Object left, Object right) {
return left instanceof Instant || right instanceof Instant;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Query :why isn't it ?

return left instanceof Instant && right instanceof Instant;

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I had the same thought at first. I looked at other comparator implementations and they did ||. It actually makes sense after I thought about it. This comparator knows whether two instants are equal, but it also knows whether one instant is equal to a non-instant, so it makes sense to say it can compare an instant and a non-instant (to return false).

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

got it, thanks 👍

@millems millems merged commit 03f2db7 into master Feb 17, 2022
@millems millems deleted the millem/jdk-17 branch October 19, 2022 19:35
aws-sdk-java-automation added a commit that referenced this pull request May 17, 2024
…4bb20707f

Pull request: release <- staging/15799bce-3545-419d-8e68-bc74bb20707f
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants