Skip to content

Commit

Permalink
Apply Nullable annotations to arrays (java-native-access#705)
Browse files Browse the repository at this point in the history
Motivation:
`Nullable` annotations give an idea of what to expect from the API.
Plus, they provide better IDE integration.

Modification:
`Nullable` annotations are applied to arrays where necessary.

Result:
The change extends the API with nullability expectations.
  • Loading branch information
simonatan authored Mar 28, 2024
1 parent d897703 commit ca5c410
Show file tree
Hide file tree
Showing 13 changed files with 45 additions and 39 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ static long SSLContext_new(boolean server, String[] applicationProtocols,
keylogCallback, sessionCallback, privateKeyMethod, sessionTicketCallback, verifyMode, subjectNames);
}

private static byte[] toWireFormat(String[] applicationProtocols) {
private static byte @Nullable [] toWireFormat(String @Nullable [] applicationProtocols) {
if (applicationProtocols == null) {
return null;
}
Expand All @@ -71,7 +71,7 @@ private static byte[] toWireFormat(String[] applicationProtocols) {
}

private static native long SSLContext_new0(boolean server,
byte[] applicationProtocols, Object handshakeCompleteCallback,
byte @Nullable [] applicationProtocols, Object handshakeCompleteCallback,
Object certificateCallback, Object verifyCallback,
@Nullable Object servernameCallback, @Nullable Object keylogCallback,
@Nullable Object sessionCallback,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ final class BoringSSLCertificateCallback {
}

@SuppressWarnings("unused")
long[] handle(long ssl, byte[] keyTypeBytes, byte[][] asn1DerEncodedPrincipals, String[] authMethods) {
long @Nullable [] handle(long ssl, byte[] keyTypeBytes, byte @Nullable [][] asn1DerEncodedPrincipals, String[] authMethods) {
QuicheQuicSslEngine engine = engineMap.get(ssl);
if (engine == null) {
return null;
Expand Down Expand Up @@ -138,14 +138,14 @@ long[] handle(long ssl, byte[] keyTypeBytes, byte[][] asn1DerEncodedPrincipals,
}
}

private long[] removeMappingIfNeeded(long ssl, long[] result) {
private long @Nullable [] removeMappingIfNeeded(long ssl, long @Nullable [] result) {
if (result == null) {
engineMap.remove(ssl);
}
return result;
}

private long[] selectKeyMaterialServerSide(long ssl, QuicheQuicSslEngine engine, String[] authMethods)
private long @Nullable [] selectKeyMaterialServerSide(long ssl, QuicheQuicSslEngine engine, String[] authMethods)
throws SSLException {
if (authMethods.length == 0) {
throw new SSLHandshakeException("Unable to find key material");
Expand All @@ -168,8 +168,8 @@ private long[] selectKeyMaterialServerSide(long ssl, QuicheQuicSslEngine engine,
+ Arrays.toString(authMethods));
}

private long[] selectKeyMaterialClientSide(long ssl, QuicheQuicSslEngine engine, String[] keyTypes,
X500Principal[] issuer) {
private long @Nullable [] selectKeyMaterialClientSide(long ssl, QuicheQuicSslEngine engine, String[] keyTypes,
X500Principal @Nullable [] issuer) {
String alias = chooseClientAlias(engine, keyTypes, issuer);
// Only try to set the keymaterial if we have a match. This is also consistent with what OpenJDK does:
// https://hg.openjdk.java.net/jdk/jdk11/file/76072a077ee1/
Expand All @@ -180,7 +180,7 @@ private long[] selectKeyMaterialClientSide(long ssl, QuicheQuicSslEngine engine,
return NO_KEY_MATERIAL_CLIENT_SIDE;
}

private long[] selectMaterial(long ssl, QuicheQuicSslEngine engine, String alias) {
private long @Nullable [] selectMaterial(long ssl, QuicheQuicSslEngine engine, String alias) {
X509Certificate[] certificates = keyManager.getCertificateChain(alias);
if (certificates == null || certificates.length == 0) {
return null;
Expand Down Expand Up @@ -213,7 +213,7 @@ private long[] selectMaterial(long ssl, QuicheQuicSslEngine engine, String alias
return new long[] { key, chain };
}

private static byte[] toPemEncoded(PrivateKey key) {
private static byte @Nullable [] toPemEncoded(PrivateKey key) {
try (ByteArrayOutputStream out = new ByteArrayOutputStream()) {
out.write(BEGIN_PRIVATE_KEY);
out.write(Base64.getEncoder().encode(key.getEncoded()));
Expand All @@ -226,7 +226,7 @@ private static byte[] toPemEncoded(PrivateKey key) {

@Nullable
private String chooseClientAlias(QuicheQuicSslEngine engine,
String[] keyTypes, X500Principal[] issuer) {
String[] keyTypes, X500Principal @Nullable [] issuer) {
return keyManager.chooseEngineClientAlias(keyTypes, issuer, engine);
}

Expand All @@ -243,7 +243,7 @@ private String chooseServerAlias(QuicheQuicSslEngine engine, String type) {
* @return supported key types that can be used in {@code X509KeyManager.chooseClientAlias} and
* {@code X509ExtendedKeyManager.chooseEngineClientAlias}.
*/
private static Set<String> supportedClientKeyTypes(byte[] clientCertificateTypes) {
private static Set<String> supportedClientKeyTypes(byte @Nullable[] clientCertificateTypes) {
if (clientCertificateTypes == null) {
// Try all of the supported key types.
return SUPPORTED_KEY_TYPES;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
package io.netty.incubator.codec.quic;

import io.netty.handler.ssl.OpenSslCertificateException;
import org.jetbrains.annotations.Nullable;

import javax.net.ssl.X509ExtendedTrustManager;
import javax.net.ssl.X509TrustManager;
Expand All @@ -42,7 +43,7 @@ final class BoringSSLCertificateVerifyCallback {
private final QuicheQuicSslEngineMap engineMap;
private final X509TrustManager manager;

BoringSSLCertificateVerifyCallback(QuicheQuicSslEngineMap engineMap, X509TrustManager manager) {
BoringSSLCertificateVerifyCallback(QuicheQuicSslEngineMap engineMap, @Nullable X509TrustManager manager) {
this.engineMap = engineMap;
this.manager = manager;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ public Key engineGetKey(String alias, char[] password) {
}

@Override
public Certificate[] engineGetCertificateChain(String alias) {
public Certificate @Nullable [] engineGetCertificateChain(String alias) {
return engineContainsAlias(alias)? certificateChain.clone() : null;
}

Expand Down Expand Up @@ -240,7 +240,7 @@ public void engineStore(OutputStream stream, char[] password) {
}

@Override
public void engineLoad(@Nullable InputStream stream, char[] password) {
public void engineLoad(@Nullable InputStream stream, char @Nullable [] password) {
if (stream != null && password != null) {
throw new UnsupportedOperationException();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ final class BoringSSLSessionCallback {
}

@SuppressWarnings("unused")
void newSession(long ssl, long creationTime, long timeout, byte[] session, boolean isSingleUse, byte[] peerParams) {
void newSession(long ssl, long creationTime, long timeout, byte[] session, boolean isSingleUse, byte @Nullable [] peerParams) {
if (sessionCache == null) {
return;
}
Expand Down Expand Up @@ -66,7 +66,7 @@ void newSession(long ssl, long creationTime, long timeout, byte[] session, boole
}

// Mimic the encoding of quiche: https://github.com/cloudflare/quiche/blob/0.10.0/src/lib.rs#L1668
private static byte[] toQuicheQuicSession(byte[] sslSession, byte[] peerParams) {
private static byte @Nullable [] toQuicheQuicSession(byte @Nullable [] sslSession, byte @Nullable [] peerParams) {
if (sslSession != null && peerParams != null) {
try (ByteArrayOutputStream bos = new ByteArrayOutputStream();
DataOutputStream dos = new DataOutputStream(bos)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,15 @@
package io.netty.incubator.codec.quic;

import io.netty.util.internal.PlatformDependent;
import org.jetbrains.annotations.Nullable;

final class BoringSSLSessionTicketCallback {

// As we dont assume to have a lot of keys configured we will just use an array for now as a data store.
private volatile byte[][] sessionKeys;

// Accessed via JNI.
byte[] findSessionTicket(byte[] keyname) {
byte @Nullable [] findSessionTicket(byte @Nullable [] keyname) {
byte[][] keys = this.sessionKeys;
if (keys == null || keys.length == 0) {
return null;
Expand All @@ -41,7 +42,7 @@ byte[] findSessionTicket(byte[] keyname) {
return null;
}

void setSessionTicketKeys(SslSessionTicketKey[] keys) {
void setSessionTicketKeys(SslSessionTicketKey @Nullable [] keys) {
if (keys != null && keys.length != 0) {
byte[][] sessionKeys = new byte[keys.length][];
for(int i = 0; i < keys.length; ++i) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ boolean hasSession(@Nullable String host, int port) {
return false;
}

byte[] getSession(@Nullable String host, int port) {
byte @Nullable [] getSession(@Nullable String host, int port) {
HostPort hostPort = keyFor(host, port);
if (hostPort != null) {
SessionHolder sessionHolder;
Expand Down Expand Up @@ -214,7 +214,7 @@ private static final class HostPort {
private final String host;
private final int port;

HostPort(String host, int port) {
HostPort(@Nullable String host, int port) {
this.host = host;
this.port = port;
// Calculate a hashCode that does ignore case.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -229,7 +229,7 @@ public QuicSslContextBuilder trustManager(@Nullable File trustCertCollectionFile
* see <a href="https://www.oracle.com/java/technologies/javase/8u261-relnotes.html">
* JDK 8u261 Update Release Notes</a>
*/
public QuicSslContextBuilder trustManager(X509Certificate... trustCertCollection) {
public QuicSslContextBuilder trustManager(X509Certificate @Nullable ... trustCertCollection) {
try {
return trustManager(QuicheQuicSslContext.buildTrustManagerFactory0(trustCertCollection));
} catch (Exception e) {
Expand Down Expand Up @@ -293,7 +293,7 @@ public QuicSslContextBuilder keyManager(@Nullable File keyFile, @Nullable String
* password-protected
* @param certChain an X.509 certificate chain
*/
public QuicSslContextBuilder keyManager(@Nullable PrivateKey key, @Nullable String keyPassword, X509Certificate... certChain) {
public QuicSslContextBuilder keyManager(@Nullable PrivateKey key, @Nullable String keyPassword, X509Certificate @Nullable ... certChain) {
try {
java.security.KeyStore ks = java.security.KeyStore.getInstance(KeyStore.getDefaultType());
ks.load(null);
Expand Down Expand Up @@ -332,7 +332,7 @@ public QuicSslContextBuilder keyManager(KeyManager keyManager, @Nullable String
/**
* Application protocol negotiation configuration. {@code null} disables support.
*/
public QuicSslContextBuilder applicationProtocols(String... applicationProtocols) {
public QuicSslContextBuilder applicationProtocols(String @Nullable ... applicationProtocols) {
this.applicationProtocols = applicationProtocols;
return this;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
*/
package io.netty.incubator.codec.quic;

import org.jetbrains.annotations.Nullable;

import javax.net.ssl.SSLSessionContext;

/**
Expand All @@ -30,5 +32,5 @@ public interface QuicSslSessionContext extends SSLSessionContext {
*
* @param keys the tickets to use.
*/
void setTicketKeys(SslSessionTicketKey... keys);
void setTicketKeys(SslSessionTicketKey @Nullable ... keys);
}
Original file line number Diff line number Diff line change
Expand Up @@ -304,6 +304,7 @@ private static void loadNativeLibrary() {
/**
* See <a href="https://github.com/cloudflare/quiche/blob/0.6.0/include/quiche.h#L105">quiche_version</a>.
*/
@Nullable
static native String quiche_version();

/**
Expand Down Expand Up @@ -368,7 +369,7 @@ static QuicConnectionCloseEvent quiche_conn_peer_error(long connAddr) {
return new QuicConnectionCloseEvent((Boolean) error[0], (Integer) error[1], (byte[]) error[2]);
}

private static native Object[] quiche_conn_peer_error0(long connAddr);
private static native Object @Nullable [] quiche_conn_peer_error0(long connAddr);

/**
* See <a href="https://github.com/cloudflare/quiche/blob/0.7.0/include/quiche.h#L330">
Expand All @@ -394,7 +395,7 @@ static native int quiche_conn_stream_priority(
/**
* See <a href="https://github.com/cloudflare/quiche/blob/0.7.0/include/quiche.h#L309">quiche_conn_trace_id</a>.
*/
static native byte[] quiche_conn_trace_id(long connAddr);
static native byte @Nullable [] quiche_conn_trace_id(long connAddr);

static native byte[] quiche_conn_source_id(long connAddr);

Expand Down Expand Up @@ -466,14 +467,14 @@ static native int quiche_conn_stream_priority(
* <a href="https://github.com/cloudflare/quiche/blob/0.6.0/include/quiche.h#L340">quiche_stats</a> being numerical.
* The assumption made allows passing primitive array rather than dealing with objects.
*/
static native long[] quiche_conn_stats(long connAddr);
static native long @Nullable [] quiche_conn_stats(long connAddr);

/**
* See
* <a href="https://github.com/cloudflare/quiche/blob/master/quiche/include/quiche.h#L567C65-L567C88">
* quiche_conn_stats</a>.
*/
static native long[] quiche_conn_peer_transport_params(long connAddr);
static native long @Nullable [] quiche_conn_peer_transport_params(long connAddr);

/**
* See
Expand Down Expand Up @@ -521,7 +522,7 @@ static native int quiche_conn_stream_priority(
* See
* <a href="https://github.com/cloudflare/quiche/blob/0.20.0/quiche/include/quiche.h#L672">quiche_conn_path_stats</a>.
*/
static native Object[] quiche_conn_path_stats(long connAddr, long streamIdx);
static native Object @Nullable [] quiche_conn_path_stats(long connAddr, long streamIdx);

/**
* See
Expand Down Expand Up @@ -570,7 +571,7 @@ static native int quiche_conn_stream_priority(

static native long quiche_conn_new_scid(long connAddr, long scidAddr, int scidLen, byte[] resetToken, boolean retire_if_needed, long seq);

static native byte[] quiche_conn_retired_scid_next(long connAddr);
static native byte @Nullable [] quiche_conn_retired_scid_next(long connAddr);

static native long quiche_conn_path_event_next(long connAddr);
static native int quiche_path_event_type(long pathEvent);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2049,6 +2049,7 @@ private void collectStats0(Promise<QuicConnectionStats> promise) {
collectStats0(connection, promise);
}

@Nullable
private QuicConnectionStats collectStats0(QuicheQuicConnection connection, Promise<QuicConnectionStats> promise) {
final long[] stats = Quiche.quiche_conn_stats(connection.address());
if (stats == null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ private static X509TrustManager chooseTrustManager(TrustManagerFactory trustMana
throw new IllegalArgumentException("No X509TrustManager included");
}

static X509Certificate[] toX509Certificates0(@Nullable File file) throws CertificateException {
static X509Certificate @Nullable [] toX509Certificates0(@Nullable File file) throws CertificateException {
return toX509Certificates(file);
}

Expand All @@ -169,7 +169,7 @@ static PrivateKey toPrivateKey0(@Nullable File keyFile, @Nullable String keyPass
}

static TrustManagerFactory buildTrustManagerFactory0(
X509Certificate[] certCollection)
X509Certificate @Nullable [] certCollection)
throws NoSuchAlgorithmException, CertificateException, KeyStoreException, IOException {
return buildTrustManagerFactory(certCollection, null, null);
}
Expand Down Expand Up @@ -344,7 +344,7 @@ void setSessionCacheSize(int size) throws IllegalArgumentException {
}
}

void setSessionTicketKeys(SslSessionTicketKey[] ticketKeys) {
void setSessionTicketKeys(SslSessionTicketKey @Nullable [] ticketKeys) {
sessionTicketCallback.setSessionTicketKeys(ticketKeys);
BoringSSL.SSLContext_setSessionTicketKeys(
nativeSslContext.address(), ticketKeys != null && ticketKeys.length != 0);
Expand All @@ -354,7 +354,7 @@ void setSessionTicketKeys(SslSessionTicketKey[] ticketKeys) {
private static final class QuicheQuicApplicationProtocolNegotiator implements ApplicationProtocolNegotiator {
private final List<String> protocols;

QuicheQuicApplicationProtocolNegotiator(String... protocols) {
QuicheQuicApplicationProtocolNegotiator(String @Nullable ... protocols) {
if (protocols == null) {
this.protocols = Collections.emptyList();
} else {
Expand Down Expand Up @@ -417,7 +417,7 @@ public int getSessionCacheSize() {
}

@Override
public void setTicketKeys(SslSessionTicketKey... keys) {
public void setTicketKeys(SslSessionTicketKey @Nullable ... keys) {
context.setSessionTicketKeys(keys);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -263,7 +263,7 @@ public boolean getEnableSessionCreation() {
synchronized void handshakeFinished(byte[] id, String cipher, String protocol, byte[] peerCertificate,
byte[][] peerCertificateChain,
long creationTime, long timeout,
byte[] applicationProtocol, boolean sessionReused) {
byte @Nullable [] applicationProtocol, boolean sessionReused) {
if (applicationProtocol == null) {
this.applicationProtocol = null;
} else {
Expand Down Expand Up @@ -296,10 +296,10 @@ private final class QuicheQuicSslSession implements SSLSession {
// lazy init for memory reasons
private Map<String, Object> values;

private boolean isEmpty(Object[] arr) {
private boolean isEmpty(Object @Nullable [] arr) {
return arr == null || arr.length == 0;
}
private boolean isEmpty(byte[] arr) {
private boolean isEmpty(byte @Nullable [] arr) {
return arr == null || arr.length == 0;
}

Expand Down Expand Up @@ -507,7 +507,7 @@ public Certificate[] getPeerCertificates() throws SSLPeerUnverifiedException {
}

@Override
public Certificate[] getLocalCertificates() {
public Certificate @Nullable [] getLocalCertificates() {
Certificate[] localCerts = localCertificateChain;
if (localCerts == null) {
return null;
Expand Down

0 comments on commit ca5c410

Please sign in to comment.