mirror of
https://github.com/apple/pkl.git
synced 2026-04-28 19:27:18 +02:00
pkl-config-java: Replace Config.fromPklBinary() with ConfigDecoder (#1533)
Motivation: - `Config` mixes configuration representation with decoding logic - `Config.fromPklBinary()` does not scale as decoding gains options (e.g., binary versions or formats) - The decoding API is inconsistent with `ConfigEvaluator` Changes: - Introduce `ConfigDecoder` (with builder) and move `Config.fromPklBinary()` logic into it - Deprecate `Config.fromPklBinary()` methods for removal - Add `ConfigDecoder.forKotlin()` extension function - Update and improve tests Result: - Decoding is separated from `Config` and exposed via a dedicated API - Decoding can evolve independently (e.g., adding options such as binary versions or supporting new formats) - Evaluation and decoding APIs follow a consistent design
This commit is contained in:
@@ -15,22 +15,19 @@
|
||||
*/
|
||||
package org.pkl.config.java;
|
||||
|
||||
import static org.pkl.config.java.ConfigUtils.makeConfig;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.lang.reflect.Type;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
import org.pkl.config.java.mapper.ConversionException;
|
||||
import org.pkl.config.java.mapper.ValueMapper;
|
||||
import org.pkl.core.Evaluator;
|
||||
import org.pkl.core.PklBinaryDecoder;
|
||||
|
||||
/**
|
||||
* A root, intermediate, or leaf node in a configuration tree. Child nodes can be obtained by name
|
||||
* using {@link #get(String)}. To consume the node's composite or scalar value, convert the value to
|
||||
* the desired Java type, using one of the provided {@link #as} methods.
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
@SuppressWarnings({"DeprecatedIsStillUsed"})
|
||||
public interface Config {
|
||||
/**
|
||||
* The dot-separated name of this node. For example, the node reached using {@code
|
||||
@@ -76,39 +73,50 @@ public interface Config {
|
||||
<T extends @Nullable Object> T as(JavaType<T> type);
|
||||
|
||||
/**
|
||||
* Decode a config from the supplied byte array.
|
||||
* Decodes a config from the supplied byte array.
|
||||
*
|
||||
* @return the encoded config
|
||||
* @return the decoded config
|
||||
* @deprecated Use {@code ConfigDecoderBuilder...build().decode(bytes)} instead. For a direct
|
||||
* equivalent, use {@code ConfigDecoder.preconfigured().setValueMapper(mapper).decode(bytes)}.
|
||||
*/
|
||||
@Deprecated(forRemoval = true)
|
||||
static Config fromPklBinary(byte[] bytes, ValueMapper mapper) {
|
||||
return makeConfig(PklBinaryDecoder.decode(bytes), mapper);
|
||||
return ConfigDecoder.preconfigured().setValueMapper(mapper).decode(bytes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Decode a config from the supplied byte array using a preconfigured {@link ValueMapper}.
|
||||
* Decodes a config from the supplied byte array using a preconfigured {@link ValueMapper}.
|
||||
*
|
||||
* @return the encoded config
|
||||
* @return the decoded config
|
||||
* @deprecated Use {@code ConfigDecoder.preconfigured().decode(bytes)} instead.
|
||||
*/
|
||||
@Deprecated(forRemoval = true)
|
||||
static Config fromPklBinary(byte[] bytes) {
|
||||
return fromPklBinary(bytes, ValueMapper.preconfigured());
|
||||
return ConfigDecoder.preconfigured().decode(bytes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Decode a config from the supplied {@link InputStream} using a preconfigured {@link
|
||||
* Decodes a config from the supplied {@link InputStream} using a preconfigured {@link
|
||||
* ValueMapper}.
|
||||
*
|
||||
* @return the encoded config
|
||||
* @return the decoded config
|
||||
* @deprecated Use {@code ConfigDecoderBuilder...build().decode(inputStream)} instead. For a
|
||||
* direct equivalent, use {@code
|
||||
* ConfigDecoder.preconfigured().setValueMapper(mapper).decode(inputStream)}.
|
||||
*/
|
||||
@Deprecated(forRemoval = true)
|
||||
static Config fromPklBinary(InputStream inputStream, ValueMapper mapper) {
|
||||
return makeConfig(PklBinaryDecoder.decode(inputStream), mapper);
|
||||
return ConfigDecoder.preconfigured().setValueMapper(mapper).decode(inputStream);
|
||||
}
|
||||
|
||||
/**
|
||||
* Decode a config from the supplied {@link InputStream}.
|
||||
* Decodes a config from the supplied {@link InputStream}.
|
||||
*
|
||||
* @return the encoded config
|
||||
* @return the decoded config
|
||||
* @deprecated Use {@code ConfigDecoder.preconfigured().decode(inputStream)} instead.
|
||||
*/
|
||||
@Deprecated(forRemoval = true)
|
||||
static Config fromPklBinary(InputStream inputStream) {
|
||||
return fromPklBinary(inputStream, ValueMapper.preconfigured());
|
||||
return ConfigDecoder.preconfigured().decode(inputStream);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* Copyright © 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.pkl.config.java;
|
||||
|
||||
import java.io.InputStream;
|
||||
import org.pkl.config.java.mapper.ValueMapper;
|
||||
|
||||
/** Decodes Pkl binary data into {@link Config} objects. */
|
||||
public interface ConfigDecoder {
|
||||
|
||||
/**
|
||||
* Returns a preconfigured decoder that uses {@link ValueMapper#preconfigured()}.
|
||||
*
|
||||
* <p>For more control over configuration, use {@link ConfigDecoderBuilder}.
|
||||
*
|
||||
* @return a preconfigured decoder
|
||||
*/
|
||||
static ConfigDecoder preconfigured() {
|
||||
return ConfigDecoderBuilder.preconfigured().build();
|
||||
}
|
||||
|
||||
ValueMapper getValueMapper();
|
||||
|
||||
/**
|
||||
* Returns a copy of this decoder with the supplied value mapper.
|
||||
*
|
||||
* @param mapper the value mapper to use
|
||||
* @return a decoder with the supplied value mapper
|
||||
*/
|
||||
ConfigDecoder setValueMapper(ValueMapper mapper);
|
||||
|
||||
/**
|
||||
* Decodes configuration from the supplied byte array.
|
||||
*
|
||||
* @param bytes the data to decode
|
||||
* @return the decoded configuration
|
||||
*/
|
||||
Config decode(byte[] bytes);
|
||||
|
||||
/**
|
||||
* Decodes configuration from the supplied input stream.
|
||||
*
|
||||
* <p>This method does not close the stream; the caller is responsible for closing it.
|
||||
*
|
||||
* @param inputStream the data to decode
|
||||
* @return the decoded configuration
|
||||
*/
|
||||
Config decode(InputStream inputStream);
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
* Copyright © 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.pkl.config.java;
|
||||
|
||||
import org.pkl.config.java.mapper.ValueMapperBuilder;
|
||||
|
||||
/**
|
||||
* Builder for {@link ConfigDecoder} instances.
|
||||
*
|
||||
* <p>Use {@link #preconfigured()} to obtain a preconfigured builder, or {@link #unconfigured()} for
|
||||
* full control over its configuration.
|
||||
*/
|
||||
public final class ConfigDecoderBuilder {
|
||||
private ValueMapperBuilder mapperBuilder;
|
||||
|
||||
private ConfigDecoderBuilder(ValueMapperBuilder mapperBuilder) {
|
||||
this.mapperBuilder = mapperBuilder;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a preconfigured builder that uses {@link ValueMapperBuilder#preconfigured()}.
|
||||
*
|
||||
* @return a preconfigured builder
|
||||
*/
|
||||
public static ConfigDecoderBuilder preconfigured() {
|
||||
return new ConfigDecoderBuilder(ValueMapperBuilder.preconfigured());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an unconfigured builder that uses {@link ValueMapperBuilder#unconfigured()}.
|
||||
*
|
||||
* @return an unconfigured builder
|
||||
*/
|
||||
public static ConfigDecoderBuilder unconfigured() {
|
||||
return new ConfigDecoderBuilder(ValueMapperBuilder.unconfigured());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value mapper builder used by this decoder builder.
|
||||
*
|
||||
* @return the value mapper builder
|
||||
*/
|
||||
public ValueMapperBuilder getValueMapperBuilder() {
|
||||
return mapperBuilder;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the value mapper builder used by this decoder builder.
|
||||
*
|
||||
* @param mapperBuilder the value mapper builder to use
|
||||
* @return this builder
|
||||
*/
|
||||
public ConfigDecoderBuilder setValueMapperBuilder(ValueMapperBuilder mapperBuilder) {
|
||||
this.mapperBuilder = mapperBuilder;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds a {@link ConfigDecoder} using the current configuration.
|
||||
*
|
||||
* @return the configured decoder
|
||||
*/
|
||||
public ConfigDecoder build() {
|
||||
return new ConfigDecoderImpl(mapperBuilder.build());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright © 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.pkl.config.java;
|
||||
|
||||
import java.io.InputStream;
|
||||
import org.pkl.config.java.mapper.ValueMapper;
|
||||
import org.pkl.core.PklBinaryDecoder;
|
||||
|
||||
final class ConfigDecoderImpl implements ConfigDecoder {
|
||||
private final ValueMapper mapper;
|
||||
|
||||
ConfigDecoderImpl(ValueMapper mapper) {
|
||||
this.mapper = mapper;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ValueMapper getValueMapper() {
|
||||
return mapper;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ConfigDecoder setValueMapper(ValueMapper mapper) {
|
||||
return new ConfigDecoderImpl(mapper);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Config decode(byte[] bytes) {
|
||||
return ConfigUtils.createConfig(PklBinaryDecoder.decode(bytes), mapper);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Config decode(InputStream inputStream) {
|
||||
return ConfigUtils.createConfig(PklBinaryDecoder.decode(inputStream), mapper);
|
||||
}
|
||||
}
|
||||
@@ -15,7 +15,7 @@
|
||||
*/
|
||||
package org.pkl.config.java;
|
||||
|
||||
import static org.pkl.config.java.ConfigUtils.makeConfig;
|
||||
import static org.pkl.config.java.ConfigUtils.createConfig;
|
||||
|
||||
import org.pkl.config.java.mapper.ValueMapper;
|
||||
import org.pkl.core.Evaluator;
|
||||
@@ -39,13 +39,13 @@ final class ConfigEvaluatorImpl implements ConfigEvaluator {
|
||||
@Override
|
||||
public Config evaluateOutputValue(ModuleSource moduleSource) {
|
||||
var value = evaluator.evaluateOutputValue(moduleSource);
|
||||
return makeConfig(value, mapper);
|
||||
return createConfig(value, mapper);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Config evaluateExpression(ModuleSource moduleSource, String expression) {
|
||||
var value = evaluator.evaluateExpression(moduleSource, expression);
|
||||
return makeConfig(value, mapper);
|
||||
return createConfig(value, mapper);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -19,16 +19,16 @@ import java.util.Map;
|
||||
import org.pkl.config.java.mapper.ValueMapper;
|
||||
import org.pkl.core.Composite;
|
||||
|
||||
class ConfigUtils {
|
||||
final class ConfigUtils {
|
||||
private ConfigUtils() {}
|
||||
|
||||
static Config makeConfig(Object decoded, ValueMapper mapper) {
|
||||
if (decoded instanceof Composite composite) {
|
||||
static Config createConfig(Object value, ValueMapper mapper) {
|
||||
if (value instanceof Composite composite) {
|
||||
return new CompositeConfig("", mapper, composite);
|
||||
}
|
||||
if (decoded instanceof Map<?, ?> map) {
|
||||
if (value instanceof Map<?, ?> map) {
|
||||
return new MapConfig("", mapper, map);
|
||||
}
|
||||
return new LeafConfig("", mapper, decoded);
|
||||
return new LeafConfig("", mapper, value);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
@@ -26,22 +26,49 @@ import org.pkl.core.PObject;
|
||||
|
||||
public abstract class AbstractConfigTest {
|
||||
|
||||
private final Config pigeonConfig = getPigeonConfig();
|
||||
private final Config pigeonModuleConfig = getPigeonModuleConfig();
|
||||
private final Config pairConfig = getPairConfig();
|
||||
private final Config mapConfig = getMapConfig();
|
||||
protected static final String pigeonText =
|
||||
"""
|
||||
pigeon {
|
||||
age = 30
|
||||
friends = List("john", "mary")
|
||||
address {
|
||||
street = "Fuzzy St."
|
||||
}
|
||||
}
|
||||
""";
|
||||
|
||||
protected abstract Config getPigeonConfig();
|
||||
protected abstract Config loadConfig(String text);
|
||||
|
||||
protected abstract Config getPigeonModuleConfig();
|
||||
private Config loadPigeonConfig() {
|
||||
return loadConfig(pigeonText);
|
||||
}
|
||||
|
||||
protected abstract Config getPairConfig();
|
||||
private Config loadPigeonModuleConfig() {
|
||||
return loadConfig(
|
||||
"""
|
||||
age = 30
|
||||
friends = List("john", "mary")
|
||||
address { street = "Fuzzy St." }
|
||||
""");
|
||||
}
|
||||
|
||||
protected abstract Config getMapConfig();
|
||||
private Config loadPairConfig() {
|
||||
return loadConfig(
|
||||
"""
|
||||
x { first = "file/path"; second = 42 }
|
||||
""");
|
||||
}
|
||||
|
||||
private Config loadMapConfig() {
|
||||
return loadConfig(
|
||||
"""
|
||||
x = Map("one", 1, "two", 2)
|
||||
""");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void navigate() {
|
||||
var pigeon = pigeonConfig.get("pigeon");
|
||||
var pigeon = loadPigeonConfig().get("pigeon");
|
||||
assertThat(pigeon.getQualifiedName()).isEqualTo("pigeon");
|
||||
assertThat(pigeon.getRawValue()).isInstanceOf(PObject.class);
|
||||
|
||||
@@ -58,7 +85,7 @@ public abstract class AbstractConfigTest {
|
||||
|
||||
@Test
|
||||
public void navigateToNonExistingObjectChild() {
|
||||
var pigeon = pigeonConfig.get("pigeon");
|
||||
var pigeon = loadPigeonConfig().get("pigeon");
|
||||
var t = catchThrowable(() -> pigeon.get("non-existing"));
|
||||
|
||||
assertThat(t)
|
||||
@@ -70,7 +97,7 @@ public abstract class AbstractConfigTest {
|
||||
|
||||
@Test
|
||||
public void navigateToNonExistingMapChild() {
|
||||
var map = mapConfig.get("x");
|
||||
var map = loadMapConfig().get("x");
|
||||
var t = catchThrowable(() -> map.get("non-existing"));
|
||||
|
||||
assertThat(t)
|
||||
@@ -81,7 +108,7 @@ public abstract class AbstractConfigTest {
|
||||
|
||||
@Test
|
||||
public void navigateToNonExistingLeafChild() {
|
||||
var age = pigeonConfig.get("pigeon").get("age");
|
||||
var age = loadPigeonConfig().get("pigeon").get("age");
|
||||
var t = catchThrowable(() -> age.get("non-existing"));
|
||||
|
||||
assertThat(t)
|
||||
@@ -92,25 +119,25 @@ public abstract class AbstractConfigTest {
|
||||
|
||||
@Test
|
||||
public void convertObjectToPojoByType() {
|
||||
Person pigeon = pigeonConfig.get("pigeon").as(Person.class);
|
||||
Person pigeon = loadPigeonConfig().get("pigeon").as(Person.class);
|
||||
checkPigeon(pigeon);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void convertObjectToPojoByJavaType() {
|
||||
var pigeon = pigeonConfig.get("pigeon").as(JavaType.of(Person.class));
|
||||
var pigeon = loadPigeonConfig().get("pigeon").as(JavaType.of(Person.class));
|
||||
checkPigeon(pigeon);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void convertModuleToPojoByType() {
|
||||
var pigeon = pigeonModuleConfig.as(Person.class);
|
||||
var pigeon = loadPigeonModuleConfig().as(Person.class);
|
||||
checkPigeon(pigeon);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void convertModuleToPojoByJavaType() {
|
||||
var pigeon = pigeonModuleConfig.as(JavaType.of(Person.class));
|
||||
var pigeon = loadPigeonModuleConfig().as(JavaType.of(Person.class));
|
||||
checkPigeon(pigeon);
|
||||
}
|
||||
|
||||
@@ -124,13 +151,15 @@ public abstract class AbstractConfigTest {
|
||||
@Test
|
||||
public void convertToParameterizedTypeByType() {
|
||||
Pair<Path, Integer> pair =
|
||||
pairConfig.get("x").as(Types.parameterizedType(Pair.class, Path.class, Integer.class));
|
||||
loadPairConfig()
|
||||
.get("x")
|
||||
.as(Types.parameterizedType(Pair.class, Path.class, Integer.class));
|
||||
checkPair(pair);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void convertToParameterizedTypeByJavaType() {
|
||||
var pair = pairConfig.get("x").as(new JavaType<Pair<Path, Integer>>() {});
|
||||
var pair = loadPairConfig().get("x").as(new JavaType<Pair<Path, Integer>>() {});
|
||||
checkPair(pair);
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright © 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.pkl.config.java;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.pkl.config.java.mapper.ConverterFactories;
|
||||
|
||||
public final class ConfigDecoderBuilderTest {
|
||||
@Test
|
||||
public void preconfiguredBuilderHasPreconfiguredMapperBuilder() {
|
||||
var builder = ConfigDecoderBuilder.preconfigured();
|
||||
var mapperBuilder = builder.getValueMapperBuilder();
|
||||
assertThat(mapperBuilder).isNotNull();
|
||||
assertThat(mapperBuilder.getConverterFactories()).isEqualTo(ConverterFactories.all);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void unconfiguredBuilderHasUnconfiguredMapperBuilder() {
|
||||
var builder = ConfigDecoderBuilder.unconfigured();
|
||||
var mapperBuilder = builder.getValueMapperBuilder();
|
||||
assertThat(mapperBuilder).isNotNull();
|
||||
assertThat(mapperBuilder.getConverterFactories()).isEmpty();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
* Copyright © 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.pkl.config.java;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import org.junit.jupiter.api.AfterAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.pkl.config.java.mapper.ValueMapper;
|
||||
import org.pkl.core.Evaluator;
|
||||
import org.pkl.core.ModuleSource;
|
||||
|
||||
public final class ConfigDecoderTest extends AbstractConfigTest {
|
||||
private static final Evaluator evaluator = Evaluator.preconfigured();
|
||||
|
||||
@AfterAll
|
||||
public static void afterAll() {
|
||||
evaluator.close();
|
||||
}
|
||||
|
||||
private ModuleSource toModuleSource(String text) {
|
||||
return ModuleSource.text(
|
||||
"""
|
||||
import "pkl:pklbinary"
|
||||
"""
|
||||
+ text
|
||||
+ """
|
||||
output {
|
||||
renderer = new pklbinary.Renderer {}
|
||||
}
|
||||
""");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Config loadConfig(String text) {
|
||||
var bytes = evaluator.evaluateOutputBytes(toModuleSource(text));
|
||||
return ConfigDecoder.preconfigured().decode(bytes);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void fromInputStream() {
|
||||
var bytes = evaluator.evaluateOutputBytes(toModuleSource(pigeonText));
|
||||
var config = ConfigDecoder.preconfigured().decode(new ByteArrayInputStream(bytes));
|
||||
assertThat(config.get("pigeon").get("age").as(Integer.class)).isEqualTo(30);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void fromBytesWithOwnValueMapper() {
|
||||
var bytes = evaluator.evaluateOutputBytes(toModuleSource(pigeonText));
|
||||
var config =
|
||||
ConfigDecoder.preconfigured().setValueMapper(ValueMapper.preconfigured()).decode(bytes);
|
||||
assertThat(config.get("pigeon").get("age").as(Integer.class)).isEqualTo(30);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void fromInputStreamWithOwnValueMapper() {
|
||||
var bytes = evaluator.evaluateOutputBytes(toModuleSource(pigeonText));
|
||||
var config =
|
||||
ConfigDecoder.preconfigured()
|
||||
.setValueMapper(ValueMapper.preconfigured())
|
||||
.decode(new ByteArrayInputStream(bytes));
|
||||
assertThat(config.get("pigeon").get("age").as(Integer.class)).isEqualTo(30);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.pkl.config.java;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import org.junit.jupiter.api.AfterAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.pkl.config.java.mapper.ValueMapper;
|
||||
import org.pkl.core.Evaluator;
|
||||
import org.pkl.core.ModuleSource;
|
||||
|
||||
@SuppressWarnings("removal")
|
||||
public final class ConfigDeprecatedApiTest extends AbstractConfigTest {
|
||||
private static final Evaluator evaluator = Evaluator.preconfigured();
|
||||
|
||||
@AfterAll
|
||||
public static void afterAll() {
|
||||
evaluator.close();
|
||||
}
|
||||
|
||||
private ModuleSource toModuleSource(String text) {
|
||||
return ModuleSource.text(
|
||||
"""
|
||||
import "pkl:pklbinary"
|
||||
"""
|
||||
+ text
|
||||
+ """
|
||||
output {
|
||||
renderer = new pklbinary.Renderer {}
|
||||
}
|
||||
""");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Config loadConfig(String text) {
|
||||
var bytes = evaluator.evaluateOutputBytes(toModuleSource(text));
|
||||
return Config.fromPklBinary(bytes);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void fromInputStream() {
|
||||
var bytes = evaluator.evaluateOutputBytes(toModuleSource(pigeonText));
|
||||
var config = Config.fromPklBinary(new ByteArrayInputStream(bytes));
|
||||
assertThat(config.get("pigeon").get("age").as(Integer.class)).isEqualTo(30);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void fromBytesWithOwnValueMapper() {
|
||||
var bytes = evaluator.evaluateOutputBytes(toModuleSource(pigeonText));
|
||||
var config = Config.fromPklBinary(bytes, ValueMapper.preconfigured());
|
||||
assertThat(config.get("pigeon").get("age").as(Integer.class)).isEqualTo(30);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void fromInputStreamWithOwnValueMapper() {
|
||||
var bytes = evaluator.evaluateOutputBytes(toModuleSource(pigeonText));
|
||||
var config = Config.fromPklBinary(new ByteArrayInputStream(bytes), ValueMapper.preconfigured());
|
||||
assertThat(config.get("pigeon").get("age").as(Integer.class)).isEqualTo(30);
|
||||
}
|
||||
}
|
||||
@@ -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,7 +22,7 @@ import org.junit.jupiter.api.Test;
|
||||
import org.pkl.config.java.mapper.ConverterFactories;
|
||||
import org.pkl.core.SecurityManagers;
|
||||
|
||||
public class ConfigEvaluatorBuilderTest {
|
||||
public final class ConfigEvaluatorBuilderTest {
|
||||
@Test
|
||||
public void preconfiguredBuilderHasPreconfiguredUnderlyingBuilders() {
|
||||
var builder = ConfigEvaluatorBuilder.preconfigured();
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright © 2025 Apple Inc. and the Pkl project authors. All rights reserved.
|
||||
* Copyright © 2025-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,49 +16,37 @@
|
||||
package org.pkl.config.java;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.pkl.core.ModuleSource.text;
|
||||
|
||||
import org.junit.jupiter.api.AfterAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.pkl.core.ModuleSource;
|
||||
|
||||
public class ConfigTest extends AbstractConfigTest {
|
||||
public final class ConfigEvaluatorTest extends AbstractConfigTest {
|
||||
private static final ConfigEvaluator evaluator = ConfigEvaluator.preconfigured();
|
||||
|
||||
private static final String pigeonText =
|
||||
"pigeon { age = 30; friends = List(\"john\", \"mary\"); address { street = \"Fuzzy St.\" } }";
|
||||
|
||||
@Override
|
||||
protected Config getPigeonConfig() {
|
||||
return evaluator.evaluate(text(pigeonText));
|
||||
@AfterAll
|
||||
public static void afterAll() {
|
||||
evaluator.close();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Config getPigeonModuleConfig() {
|
||||
return evaluator.evaluate(
|
||||
text("age = 30; friends = List(\"john\", \"mary\"); address { street = \"Fuzzy St.\" }"));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Config getPairConfig() {
|
||||
return evaluator.evaluate(text("x { first = \"file/path\"; second = 42 }"));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Config getMapConfig() {
|
||||
return evaluator.evaluate(text("x = Map(\"one\", 1, \"two\", 2)"));
|
||||
protected Config loadConfig(String text) {
|
||||
return evaluator.evaluate(ModuleSource.text(text));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void evaluateOutputValue() {
|
||||
var valueConfig =
|
||||
evaluator.evaluateOutputValue(
|
||||
text(pigeonText + "\noutput { value = (outer) { pigeon { age = 99 } } }"));
|
||||
ModuleSource.text(pigeonText + "\noutput { value = (outer) { pigeon { age = 99 } } }"));
|
||||
var pigeon = valueConfig.get("pigeon").as(Person.class);
|
||||
assertThat(pigeon.age).isEqualTo(99);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void evaluateExpression() {
|
||||
var addressConfig = evaluator.evaluateExpression(text(pigeonText), "pigeon.address");
|
||||
var addressConfig =
|
||||
evaluator.evaluateExpression(ModuleSource.text(pigeonText), "pigeon.address");
|
||||
var address = addressConfig.as(Address.class);
|
||||
assertThat(address.street).isEqualTo("Fuzzy St.");
|
||||
}
|
||||
@@ -1,56 +0,0 @@
|
||||
/*
|
||||
* Copyright © 2024-2025 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.pkl.config.java;
|
||||
|
||||
import java.util.Base64;
|
||||
|
||||
public class ConfigPklBinaryDecoderTest extends AbstractConfigTest {
|
||||
// generate via: pbpaste | ./pkl-cli/build/executable/jpkl eval /dev/stdin -f pkl-binary | base64
|
||||
|
||||
@Override
|
||||
protected Config getPigeonConfig() {
|
||||
// pigeon { age = 30; friends = List("john", "mary"); address { street = "Fuzzy St." } }
|
||||
return Config.fromPklBinary(
|
||||
Base64.getDecoder()
|
||||
.decode(
|
||||
"lAGkdGVzdNklZmlsZTovLy9Vc2Vycy9qYmFzY2gvc3JjL3BrbC90ZXN0LnBrbJGTEKZwaWdlb26UAadEeW5hbWljqHBrbDpiYXNlk5MQo2FnZR6TEKdmcmllbmRzkgSSpGpvaG6kbWFyeZMQp2FkZHJlc3OUAadEeW5hbWljqHBrbDpiYXNlkZMQpnN0cmVldKlGdXp6eSBTdC4="));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Config getPigeonModuleConfig() {
|
||||
// age = 30; friends = List("john", "mary"); address { street = "Fuzzy St." }
|
||||
return Config.fromPklBinary(
|
||||
Base64.getDecoder()
|
||||
.decode(
|
||||
"lAGlc3RkaW6xZmlsZTovLy9kZXYvc3RkaW6TkxCjYWdlHpMQp2ZyaWVuZHOSBJKkam9obqRtYXJ5kxCnYWRkcmVzc5QBp0R5bmFtaWOocGtsOmJhc2WRkxCmc3RyZWV0qUZ1enp5IFN0Lg=="));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Config getPairConfig() {
|
||||
// x { first = "file/path"; second = 42 }
|
||||
return Config.fromPklBinary(
|
||||
Base64.getDecoder()
|
||||
.decode(
|
||||
"lAGlc3RkaW6xZmlsZTovLy9kZXYvc3RkaW6RkxCheJQBp0R5bmFtaWOocGtsOmJhc2WSkxClZmlyc3SpZmlsZS9wYXRokxCmc2Vjb25kKg=="));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Config getMapConfig() {
|
||||
// x = Map("one", 1, "two", 2)
|
||||
return Config.fromPklBinary(
|
||||
Base64.getDecoder().decode("lAGlc3RkaW6xZmlsZTovLy9kZXYvc3RkaW6RkxCheJICgqNvbmUBo3R3bwI="));
|
||||
}
|
||||
}
|
||||
@@ -25,7 +25,7 @@ import org.junit.jupiter.api.Test;
|
||||
import org.pkl.config.java.mapper.Reflection;
|
||||
import org.pkl.config.java.mapper.Types;
|
||||
|
||||
public class JavaTypeTest {
|
||||
public final class JavaTypeTest {
|
||||
@Test
|
||||
public void constructOptionalType() {
|
||||
var type = JavaType.optionalOf(String.class);
|
||||
|
||||
Reference in New Issue
Block a user