pkl-config-java: Migrate nullness to jSpecify (#1528)

This commit is contained in:
odenix
2026-04-17 16:56:12 +01:00
committed by GitHub
parent 2dd0e2de21
commit 1571d72111
29 changed files with 113 additions and 80 deletions

View File

@@ -1,5 +1,5 @@
/*
* Copyright © 2024-2025 Apple Inc. and the Pkl project authors. All rights reserved.
* Copyright © 2024-2026 Apple Inc. and the Pkl project authors. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -18,6 +18,7 @@ package org.pkl.config.java;
import java.io.InputStream;
import java.lang.reflect.Type;
import java.util.Map;
import org.jspecify.annotations.Nullable;
import org.pkl.config.java.mapper.ConversionException;
import org.pkl.config.java.mapper.ValueMapper;
import org.pkl.core.Composite;
@@ -55,7 +56,7 @@ public interface Config {
*
* @throws ConversionException if the value cannot be converted to the given type
*/
<T> T as(Class<T> type);
<T extends @Nullable Object> T as(Class<T> type);
/**
* Converts this node's value to the given {@link Type}.
@@ -64,14 +65,14 @@ public interface Config {
*
* @throws ConversionException if the value cannot be converted to the given type
*/
<T> T as(Type type);
<T extends @Nullable Object> T as(Type type);
/**
* Converts this node's value to the given {@link JavaType}.
*
* @throws ConversionException if the value cannot be converted to the given type
*/
<T> T as(JavaType<T> type);
<T extends @Nullable Object> T as(JavaType<T> type);
/**
* Decode a config from the supplied byte array.

View File

@@ -1,5 +1,5 @@
/*
* Copyright © 2024-2025 Apple Inc. and the Pkl project authors. All rights reserved.
* Copyright © 2024-2026 Apple Inc. and the Pkl project authors. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -21,6 +21,7 @@ import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;
import org.jspecify.annotations.Nullable;
import org.pkl.config.java.mapper.ValueMapperBuilder;
import org.pkl.core.EvaluatorBuilder;
import org.pkl.core.SecurityManager;
@@ -28,7 +29,6 @@ import org.pkl.core.StackFrameTransformer;
import org.pkl.core.http.HttpClient;
import org.pkl.core.project.DeclaredDependencies;
import org.pkl.core.project.Project;
import org.pkl.core.util.Nullable;
/** A builder for {@link ConfigEvaluator}s. */
@SuppressWarnings({"UnusedReturnValue", "unused"})

View File

@@ -1,5 +1,5 @@
/*
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
* Copyright © 2024-2026 Apple Inc. and the Pkl project authors. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -18,9 +18,9 @@ package org.pkl.config.java;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.*;
import org.jspecify.annotations.Nullable;
import org.pkl.config.java.mapper.Types;
import org.pkl.core.Pair;
import org.pkl.core.util.Nullable;
/**
* Runtime representation of a possibly parameterized Java type. Factory methods are provided to

View File

@@ -1,5 +1,5 @@
/*
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
* Copyright © 2024-2026 Apple Inc. and the Pkl project authors. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -20,10 +20,10 @@ import java.io.UncheckedIOException;
import java.util.HashSet;
import java.util.Properties;
import java.util.Set;
import org.jspecify.annotations.Nullable;
import org.pkl.config.java.InvalidMappingException;
import org.pkl.core.PClassInfo;
import org.pkl.core.util.IoUtils;
import org.pkl.core.util.Nullable;
/**
* Describes mappings of Pkl class names to their corresponding Java classes.

View File

@@ -1,5 +1,5 @@
/*
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
* Copyright © 2024-2026 Apple Inc. and the Pkl project authors. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -15,13 +15,15 @@
*/
package org.pkl.config.java.mapper;
import org.jspecify.annotations.Nullable;
/** Thrown when a {@link ValueMapper} conversion fails. */
public class ConversionException extends RuntimeException {
public ConversionException(String message) {
super(message);
}
public ConversionException(String message, Throwable cause) {
public ConversionException(String message, @Nullable Throwable cause) {
super(message, cause);
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
* Copyright © 2024-2026 Apple Inc. and the Pkl project authors. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -15,6 +15,8 @@
*/
package org.pkl.config.java.mapper;
import org.jspecify.annotations.Nullable;
/**
* Converter for a particular source and target type.
*
@@ -22,7 +24,7 @@ package org.pkl.config.java.mapper;
* @param <T> the converter's target type
*/
@FunctionalInterface
public interface Converter<S, T> {
public interface Converter<S, T extends @Nullable Object> {
/**
* Converts the given value. The given {@link ValueMapper} can be used to convert nested values of
* composite values (objects, collections, etc.).

View File

@@ -1,5 +1,5 @@
/*
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
* Copyright © 2024-2026 Apple Inc. and the Pkl project authors. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -19,8 +19,8 @@ import java.lang.reflect.Array;
import java.lang.reflect.Type;
import java.util.Collection;
import java.util.Optional;
import org.jspecify.annotations.Nullable;
import org.pkl.core.PClassInfo;
import org.pkl.core.util.Nullable;
final class PCollectionToArray implements ConverterFactory {
@Override

View File

@@ -1,5 +1,5 @@
/*
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
* Copyright © 2024-2026 Apple Inc. and the Pkl project authors. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -23,8 +23,8 @@ import java.lang.reflect.Type;
import java.util.Collection;
import java.util.Optional;
import java.util.function.Function;
import org.jspecify.annotations.Nullable;
import org.pkl.core.PClassInfo;
import org.pkl.core.util.Nullable;
class PCollectionToCollection implements ConverterFactory {
private static final Lookup lookup = MethodHandles.lookup();

View File

@@ -1,5 +1,5 @@
/*
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
* Copyright © 2024-2026 Apple Inc. and the Pkl project authors. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -24,8 +24,8 @@ import java.util.Map;
import java.util.Optional;
import java.util.Properties;
import java.util.function.Function;
import org.jspecify.annotations.Nullable;
import org.pkl.core.PClassInfo;
import org.pkl.core.util.Nullable;
class PMapToMap implements ConverterFactory {
private static final Lookup lookup = MethodHandles.lookup();

View File

@@ -1,5 +1,5 @@
/*
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
* Copyright © 2024-2026 Apple Inc. and the Pkl project authors. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -22,10 +22,10 @@ import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodHandles.Lookup;
import java.lang.reflect.*;
import java.util.*;
import org.jspecify.annotations.Nullable;
import org.pkl.core.Composite;
import org.pkl.core.PClassInfo;
import org.pkl.core.PObject;
import org.pkl.core.util.Nullable;
public class PObjectToDataObject implements ConverterFactory {
private static final Lookup lookup = MethodHandles.lookup();
@@ -156,7 +156,7 @@ public class PObjectToDataObject implements ConverterFactory {
private final MethodHandle constructorHandle;
private final Collection<Tuple2<String, Type>> parameters;
private final PClassInfo<Object>[] cachedPropertyTypes;
private final Converter<Object, T>[] cachedConverters;
private final @Nullable Converter<Object, T>[] cachedConverters;
ConverterImpl(
Type targetType,
@@ -172,7 +172,7 @@ public class PObjectToDataObject implements ConverterFactory {
Arrays.fill(cachedPropertyTypes, PClassInfo.Unavailable);
@SuppressWarnings("unchecked")
Converter<Object, T>[] cachedConverters = new Converter[parameters.size()];
@Nullable Converter<Object, T>[] cachedConverters = new Converter[parameters.size()];
this.cachedConverters = cachedConverters;
}
@@ -203,8 +203,9 @@ public class PObjectToDataObject implements ConverterFactory {
cachedPropertyTypes[i] = cachedPropertyType;
cachedConverters[i] = valueMapper.getConverter(cachedPropertyType, param.second);
}
assert cachedConverters[i] != null;
args[i] = cachedConverters[i].convert(property, valueMapper);
var cachedConverter = cachedConverters[i];
assert cachedConverter != null;
args[i] = cachedConverter.convert(property, valueMapper);
i += 1;
} catch (ConversionException e) {
throw new ConversionException(

View File

@@ -1,5 +1,5 @@
/*
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
* Copyright © 2024-2026 Apple Inc. and the Pkl project authors. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -18,9 +18,9 @@ package org.pkl.config.java.mapper;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Optional;
import org.jspecify.annotations.Nullable;
import org.pkl.core.PClassInfo;
import org.pkl.core.Pair;
import org.pkl.core.util.Nullable;
final class PPairToPair implements ConverterFactory {
@Override

View File

@@ -1,5 +1,5 @@
/*
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
* Copyright © 2024-2026 Apple Inc. and the Pkl project authors. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -46,12 +46,16 @@ final class PStringToEnum implements ConverterFactory {
if (enumType == DataSizeUnit.class) {
for (var value : values) {
var unit = (DataSizeUnit) value;
enumValuesByName.put(CodeGeneratorUtils.toEnumConstantName(unit.getSymbol()), value);
var name = CodeGeneratorUtils.toEnumConstantName(unit.getSymbol());
assert name != null;
enumValuesByName.put(name, value);
}
} else if (enumType == DurationUnit.class) {
for (var value : values) {
var unit = (DurationUnit) value;
enumValuesByName.put(CodeGeneratorUtils.toEnumConstantName(unit.getSymbol()), value);
var name = CodeGeneratorUtils.toEnumConstantName(unit.getSymbol());
assert name != null;
enumValuesByName.put(name, value);
}
} else {
for (Enum<?> value : values) {

View File

@@ -1,5 +1,5 @@
/*
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
* Copyright © 2024-2026 Apple Inc. and the Pkl project authors. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -20,7 +20,7 @@ import static java.util.Arrays.stream;
import io.leangen.geantyref.CaptureType;
import io.leangen.geantyref.GenericTypeReflector;
import java.lang.reflect.*;
import org.pkl.core.util.Nullable;
import org.jspecify.annotations.Nullable;
/**
* Reflection utilities for implementing {@link ConverterFactory}s. Mostly covers introspection of

View File

@@ -1,5 +1,5 @@
/*
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
* Copyright © 2024-2026 Apple Inc. and the Pkl project authors. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,7 +16,7 @@
package org.pkl.config.java.mapper;
import java.util.Objects;
import org.pkl.core.util.Nullable;
import org.jspecify.annotations.Nullable;
// avoid name clash with org.pkl.core.Pair
final class Tuple2<S, T> {

View File

@@ -1,5 +1,5 @@
/*
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
* Copyright © 2024-2026 Apple Inc. and the Pkl project authors. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,7 +16,7 @@
package org.pkl.config.java.mapper;
import java.lang.reflect.Modifier;
import org.pkl.core.util.Nullable;
import org.jspecify.annotations.Nullable;
/**
* Maps a type requested during conversion to the implementation type to be instantiated. The

View File

@@ -1,5 +1,5 @@
/*
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
* Copyright © 2024-2026 Apple Inc. and the Pkl project authors. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,6 +16,7 @@
package org.pkl.config.java.mapper;
import java.lang.reflect.Type;
import org.jspecify.annotations.Nullable;
import org.pkl.core.PClassInfo;
import org.pkl.core.PModule;
@@ -30,38 +31,40 @@ public interface ValueMapper {
}
/**
* Converts the given Pkl object to the given Java target type. The Pkl object can be an entire
* Converts the given Pkl value to the given Java target type. The Pkl value can be an entire
* {@link PModule} or any value contained therein. See {@link PClassInfo#forValue} for which Java
* types are used to represent Pkl objects.
* types are used to represent Pkl values.
*
* <p>When mapping to a generic target type, a fully parameterized type needs to be passed, e.g.
* {@code List<String>}. Parameterized type literals can be created using {@link Types}, e.g.
* {@code Types.listOf(String.class)}.
*
* <p>If an error occurs during conversion, or if {@link ValueMapper} does not know how to convert
* from the given object to the given target type, a {@link ConversionException} is thrown.
* from the given Pkl value to the given target type, a {@link ConversionException} is thrown.
*/
<S, T> T map(S model, Type targetType);
<S, T extends @Nullable Object> T map(S value, Type targetType);
/**
* Same as {@link #map(Object, Type)}, except that the target type is narrowed from {@link Type}
* to {@link Class} to allow for better type inference.
*/
default <S, T> T map(S model, Class<T> targetType) {
return map(model, (Type) targetType);
default <S, T extends @Nullable Object> T map(S value, Class<T> targetType) {
return map(value, (Type) targetType);
}
/**
* Returns the converter with the given source and target types. Throws {@link
* ConversionException} if no such converter exists.
*/
<S, T> Converter<S, T> getConverter(PClassInfo<S> sourceType, Type targetType);
<S, T extends @Nullable Object> Converter<S, T> getConverter(
PClassInfo<S> sourceType, Type targetType);
/**
* Same as {@link #getConverter(PClassInfo, Type)}, except that the target type is narrowed from
* {@link Type} to {@link Class} to allow for better type inference.
*/
default <S, T> Converter<S, T> getConverter(PClassInfo<S> sourceType, Class<T> targetType) {
default <S, T extends @Nullable Object> Converter<S, T> getConverter(
PClassInfo<S> sourceType, Class<T> targetType) {
return getConverter(sourceType, (Type) targetType);
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
* Copyright © 2024-2026 Apple Inc. and the Pkl project authors. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -52,9 +52,9 @@ class ValueMapperImpl implements ValueMapper {
@Override
@SuppressWarnings("unchecked")
public <S, T> T map(S model, Type targetType) {
var sourceType = PClassInfo.forValue(model);
return (T) getConverter(sourceType, targetType).convert(model, this);
public <S, T> T map(S value, Type targetType) {
var sourceType = PClassInfo.forValue(value);
return (T) getConverter(sourceType, targetType).convert(value, this);
}
private <S> Class<?> getTargetType(PClassInfo<S> sourceType, Type targetType) {

View File

@@ -1,4 +1,4 @@
@NonnullByDefault
@NullMarked
package org.pkl.config.java.mapper;
import org.pkl.core.util.NonnullByDefault;
import org.jspecify.annotations.NullMarked;

View File

@@ -1,4 +1,4 @@
@NonnullByDefault
@NullMarked
package org.pkl.config.java;
import org.pkl.core.util.NonnullByDefault;
import org.jspecify.annotations.NullMarked;

View File

@@ -1,5 +1,5 @@
/*
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
* Copyright © 2024-2026 Apple Inc. and the Pkl project authors. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -22,11 +22,11 @@ import java.util.EnumSet;
import java.util.Objects;
import java.util.Set;
import javax.inject.Named;
import org.jspecify.annotations.Nullable;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.Test;
import org.pkl.core.Evaluator;
import org.pkl.core.PModule;
import org.pkl.core.util.Nullable;
public class PObjectToDataObjectJavaxInjectTest {
private static final Evaluator evaluator = Evaluator.preconfigured();

View File

@@ -1,5 +1,5 @@
/*
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
* Copyright © 2024-2026 Apple Inc. and the Pkl project authors. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -20,11 +20,11 @@ import static org.pkl.core.ModuleSource.modulePath;
import java.beans.ConstructorProperties;
import java.util.*;
import org.jspecify.annotations.Nullable;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.Test;
import org.pkl.core.Evaluator;
import org.pkl.core.PModule;
import org.pkl.core.util.Nullable;
public class PObjectToDataObjectTest {
private static final Evaluator evaluator = Evaluator.preconfigured();

View File

@@ -1,5 +1,5 @@
/*
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
* Copyright © 2024-2026 Apple Inc. and the Pkl project authors. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -15,7 +15,7 @@
*/
package org.pkl.config.java.mapper;
import org.pkl.core.util.Nullable;
import org.jspecify.annotations.Nullable;
public class Person {
public final String name;