Initial commit

This commit is contained in:
Peter Niederwieser
2016-01-19 14:51:19 +01:00
committed by Dan Chao
commit ecad035dca
2972 changed files with 211653 additions and 0 deletions

View File

@@ -0,0 +1,22 @@
import org.pkl.config.java.Config;
import org.pkl.config.java.ConfigEvaluator;
import org.pkl.config.java.JavaType;
import org.junit.jupiter.api.Test;
@SuppressWarnings("unused")
// the pkl/pkl-examples repo has a similar example
public class JavaConfigExample {
@Test
public void usage() {
// tag::usage[]
Config config;
try (var evaluator = ConfigEvaluator.preconfigured()) { // <1>
config = evaluator.evaluateText(
"pigeon { age = 5; diet = \"Seeds\" }"); // <2>
}
var pigeon = config.get("pigeon"); // <3>
var age = pigeon.get("age").as(int.class); // <4>
var diet = pigeon.get("diet").as(JavaType.listOf(String.class)); // <5>
// end::usage[]
}
}

View File

@@ -0,0 +1,180 @@
= Java Code Generator
include::ROOT:partial$component-attributes.adoc[]
:uri-pkl-codgen-java-maven-module: {uri-maven-docsite}/artifact/org.pkl-lang/pkl-codegen-java
The Java source code generator takes Pkl class definitions as an input, and generates corresponding Java classes with equally named properties.
The benefits of code generation are:
* Configuration can be conveniently consumed as statically typed Java objects.
* The entire configuration tree can be code-completed in Java IDEs.
* Any drift between Java code and Pkl configuration structure is caught at compile time.
The generated classes are immutable and have component-wise implementations of `equals()`, `hashCode()`, and `toString()`.
== Installation
The code generator is offered as Gradle plugin, Java library, and CLI.
=== Gradle Plugin
See xref:pkl-gradle:index.adoc#installation[Installation] in the Gradle plugin chapter.
[[install-library]]
=== Java Library
The `pkl-codegen-java` library is available {uri-pkl-codgen-java-maven-module}[from Maven Central].
It requires Java 11 or higher.
ifndef::is-release-version[]
NOTE: Snapshots are published to repository `{uri-sonatype}`.
endif::[]
==== Gradle
To use the library in a Gradle project, declare the following dependency:
[tabs]
====
Groovy::
+
.build.gradle
[source,groovy,subs="+attributes"]
----
dependencies {
compile "org.pkl-lang:pkl-codegen-java:{pkl-artifact-version}"
}
ifndef::is-release-build[]
repositories {
maven { url "{uri-sonatype}" }
}
endif::[]
----
Kotlin::
+
.build.gradle.kts
[source,kotlin,subs="+attributes"]
----
dependencies {
compile("org.pkl-lang:pkl-codegen-java:{pkl-artifact-version}")
}
ifndef::is-release-build[]
repositories {
maven { url = uri("{uri-sonatype}") }
}
endif::[]
----
====
==== Maven
To use the library in a Maven project, declare the following dependency:
.pom.xml
[source,xml,subs="+attributes"]
----
<project>
<dependency>
<groupId>org.pkl-lang</groupId>
<artifactId>pkl-codegen-java</artifactId>
<version>{pkl-artifact-version}</version>
</dependency>
ifndef::is-release-build[]
<repositories>
<repository>
<id>sonatype-s01</id>
<name>Sonatype S01</name>
<url>{uri-sonatype}</url>
</repository>
</repositories>
endif::[]
</project>
----
[[install-cli]]
=== CLI
The CLI is bundled with the Java library.
As we do not currently ship the CLI as a self-contained Jar, we recommend to provision it with a Maven compatible build tool as shown in <<install-library>>.
[[codegen-java-usage]]
== Usage
The code generator is offered as Gradle plugin, Java library, and CLI.
=== Gradle Plugin
See xref:pkl-gradle:index.adoc#java-code-gen[Java Code Generation] in the Gradle plugin chapter.
=== Java Library
The Java library offers two APIs: a high-level API that corresponds to the CLI, and a lower-level API that provides additional features and control.
The entry points for these APIs are `org.pkl.codegen.java.CliJavaCodeGenerator` and `org.pkl.codegen.java.JavaCodeGenerator`, respectively.
For more information, refer to the Javadoc documentation.
=== CLI
As explained in <<install-cli,Installation>>, the CLI is bundled with the Java library.
To run the CLI, execute the library Jar or its `org.pkl.codegen.java.Main` main class.
*Synopsis:* `java -cp <classpath> -jar pkl-codegen-java.jar [<options>] <modules>`
`<modules>`::
The absolute or relative URIs of the modules to generate classes for.
Relative URIs are resolved against the working directory.
==== Options
.--generate-getters
[%collapsible]
====
Default: (flag not set) +
Flag that indicates to generate private final fields and public getter methods instead of public final fields.
====
.--generate-javadoc
[%collapsible]
====
Default: (flag not set) +
Flag that indicates to generate Javadoc based on doc comments for Pkl modules, classes, and properties.
====
.--params-annotation
[%collapsible]
====
Default: `org.pkl.config.java.mapper.Named` +
Fully qualified name of the annotation to use on constructor parameters.
====
.--non-null-annotation
[%collapsible]
====
Default: `org.pkl.config.java.mapper.NonNull` +
Fully qualified named of the annotation class to use for non-null types. +
This annotation is required to have `java.lang.annotation.ElementType.TYPE_USE` as a `@Target`
or it may generate code that does not compile.
====
.--implement-serializable
[%collapsible]
====
Default: (flag not set) +
Whether to make generated classes implement `java.io.Serializable`.
====
Common code generator options:
include::{partialsdir}/cli-codegen-options.adoc[]
Common CLI options:
include::../../pkl-cli/partials/cli-common-options.adoc[]
[[full-example]]
== Full Example
For a ready-to-go example with full source code,
see link:{uri-codegen-java-example}[codegen-java] in the _pkl/pkl-examples_ repository.

View File

@@ -0,0 +1,4 @@
= Integration with Java
Pkl provides rich integration with Java. Our integration allows you to embed the Pkl runtime into your Java program, and also provides code generation from Pkl source files.

View File

@@ -0,0 +1,212 @@
= pkl-config-java Library
include::ROOT:partial$component-attributes.adoc[]
:uri-pkl-core-EvalException: {uri-pkl-core-main-sources}/EvalException.java
:uri-pkl-config-java-maven-module: {uri-maven-docsite}/artifact/org.pkl-lang/pkl-config-java-all
:uri-pkl-config-java-main-sources: {uri-github-tree}/pkl-config-java/src/main/java/org/pkl/config/java
:uri-pkl-config-java-test-sources: {uri-github-tree}/pkl-config-java/src/test/java/org/pkl/config/java
:uri-pkl-config-java-test-resources: {uri-github-tree}/pkl-config-java/src/test/resources/org/pkl/config/java
:uri-pkl-config-java-ConfigEvaluator: {uri-pkl-config-java-main-sources}/ConfigEvaluator.java
:uri-pkl-config-java-Config: {uri-pkl-config-java-main-sources}/Config.java
:uri-pkl-config-java-ValueMapper: {uri-pkl-config-java-main-sources}/mapper/ValueMapper.java
:uri-pkl-config-java-Named: {uri-pkl-config-java-main-sources}/mapper/Named.java
:uri-pkl-config-java-Conversion: {uri-pkl-config-java-main-sources}/mapper/Conversion.java
:uri-pkl-config-java-Conversions: {uri-pkl-config-java-main-sources}/mapper/Conversions.java
:uri-pkl-config-java-ConverterFactories: {uri-pkl-config-java-main-sources}/mapper/ConverterFactories.java
:uri-pkl-config-java-Converter: {uri-pkl-config-java-main-sources}/mapper/Converter.java
:uri-pkl-config-java-ConverterFactory: {uri-pkl-config-java-main-sources}/mapper/ConverterFactory.java
:uri-pkl-config-java-PObjectToObjectByCtorTestJava: {uri-pkl-config-java-test-sources}/mapper/PObjectToObjectByCtorTest.java
:uri-pkl-config-java-PObjectToObjectByCtorTestPkl: {uri-pkl-config-java-test-resources}/mapper/PObjectToObjectByCtorTest.pkl
The _pkl-config-java_ library builds upon xref:pkl-core:index.adoc[pkl-core].
It offers a higher-level API specifically designed for consuming application runtime configuration.
== Installation
The _pkl-config-java_ library is available {uri-pkl-config-java-maven-module}[from Maven Central].
It requires Java 11 or higher.
=== Gradle
To use the library in a Gradle project, declare the following dependency:
[tabs]
====
Groovy::
+
.build.gradle
[source,groovy,subs="+attributes"]
----
dependencies {
compile "org.pkl-lang:pkl-config-java:{pkl-artifact-version}"
}
ifndef::is-release-build[]
repositories {
maven { url "{uri-sonatype}" }
}
endif::[]
----
Kotlin::
+
.build.gradle.kts
[source,kotlin,subs="+attributes"]
----
dependencies {
compile("org.pkl-lang:pkl-config-java:{pkl-artifact-version}")
}
ifndef::is-release-build[]
repositories {
maven { url = uri("{uri-sonatype}") }
}
endif::[]
----
====
Unlike `pkl-config-java`, `pkl-config-java__-all__` is a fat Jar with renamed third-party packages to avoid version conflicts.
=== Maven
To use the library in a Maven project, declare the following dependency:
.pom.xml
[source,xml,subs="+attributes"]
----
<project>
<dependency>
<groupId>org.pkl-lang</groupId>
<artifactId>pkl-config-java</artifactId>
<version>{pkl-artifact-version}</version>
</dependency>
ifndef::is-release-build[]
<repositories>
<repository>
<id>sonatype-s01</id>
<name>Sonatype S01</name>
<url>{uri-sonatype}</url>
</repository>
</repositories>
endif::[]
</project>
----
Unlike `pkl-config-java`, `pkl-config-java__-all__` is a fat Jar with renamed third-party packages to avoid version conflicts.
== Usage
=== Consuming Configuration
The {uri-pkl-config-java-ConfigEvaluator}[`ConfigEvaluator`] class loads and evaluates Pkl modules.
If evaluation succeeds, a {uri-pkl-config-java-Config}[`Config`] object is returned.
Otherwise, an {uri-pkl-core-EvalException}[`EvalException`] with error details is thrown.
The returned `Config` object represents the root of the Pkl configuration tree.
Intermediate and leaf nodes are also represented as `Config` objects.
`Config` objects offer methods to
* convert their Pkl value to a Java value of the specified type.
* navigate to child nodes.
Let's see this in action:
[[config-evaluator-java-example]]
[source,java,indent=0]
----
include::{examplesdir}/JavaConfigExample.java[tags=usage]
----
<1> Create a preconfigured `ConfigEvaluator`.
To create a customized evaluator, start from `ConfigEvaluatorBuilder.preconfigured()` or `ConfigEvaluatorBuilder.unconfigured()`.
The evaluator should be closed once it is no longer needed.
In this example, this is done with a try-with-resources statement.
Note that objects returned by the evaluator remain valid after calling `close()`.
<2> Evaluate the given text.
Other `evaluate` methods read from files, URLs, and other sources.
If evaluation fails, an {uri-pkl-core-EvalException}[`EvalException`] is thrown.
<3> Navigate from the config root to its `"pigeon"` child.
<4> Navigate from `"pigeon"` to `"age"` and get the latter's value as an `int`.
If conversion to the requested type fails, a `ConversionException` is thrown.
<5> Navigate from `"pigeon"` to `"diet"` and get the latter's value as a `List<String>`.
Note the use of `JavaType.listOf()` for creating a parameterized type literal.
Similar methods exist for sets, maps, and other generic types.
A `ConfigEvaluator` caches module sources and evaluation results.
To clear the cache, for example to evaluate the same module again, close the evaluator and create a new one.
For a ready-to-go example with full source code,
see link:{uri-config-java-example}[config-java] in the _pkl/pkl-examples_ repository.
[[object-mapping]]
=== Object Mapping
When a `Config` object needs to convert its Pkl value to a Java value, it delegates the conversion to {uri-pkl-config-java-ValueMapper}[`ValueMapper`].
`ValueMapper` can convert an entire `PModule` or any part thereof.
A `ValueMapper` instance can be configured with many different Pkl-to-Java value conversions.
`ValueMapper.preconfigured()` creates an instance configured with conversions from Pkl values to:
* Number types
* Strings
* Enums
* Collections
* Arrays
* `java.util.Optional`
* `java.time.Duration`
* `java.net.URI/URL`
* etc.
Additionally, a preconfigured `ValueMapper` instance can convert Pkl objects to Java objects with equally named properties that are settable through a constructor.
This conversion works as follows:
. Find the Java class constructor with the highest number of parameters.
. Match constructor parameters with Pkl object properties by name.
+
Unmatched constructor parameters result in a conversion error.
Unmatched Pkl object properties are ignored.
+
. Convert each Pkl property value to the corresponding constructor parameter's type.
. Invoke the constructor.
The Pkl object's runtime type is irrelevant to this conversion.
Hence, typed and dynamic Pkl objects are equally supported.
To perform this conversion, `ValueMapper` needs a way to obtain the Java constructor's parameter names.
They need to be provided in one of the following ways:
* Annotate constructor with `java.beans.ConstructorProperties`.
* Annotate parameters with {uri-pkl-config-java-Named}[`Named`].
* Annotate parameters with `javax.inject.Named`.
* Set the Java compiler flag `-parameters`.
For a complete object mapping example, see:
* {uri-pkl-config-java-PObjectToObjectByCtorTestJava}[`PObjectToObjectByCtorTest.java`]
TIP: Together with xref:java-binding:codegen.adoc[code generation], object mapping provides a complete solution for consuming Pkl configuration as statically typed Java objects.
Java code never drifts from the configuration structure defined in Pkl, and the entire configuration tree can be code-completed in Java IDEs.
==== Value Conversions
The Pkl-to-Java value conversions that ship with the library are defined in {uri-pkl-config-java-Conversions}[`Conversions`] (for individual conversions) and {uri-pkl-config-java-ConverterFactories}[`ConverterFactories`] (for families of conversions).
To implement and register your own conversions, follow these steps:
. For conversions from a single source type to a single target type, implement a {uri-pkl-config-java-Conversion}[`Conversion`].
+
Example: `Conversions.pStringToCharacter` converts a single-character `pkl.base#String` to `java.lang.Character`.
. For conversions from one or multiple source types to one or multiple target types, implement a {uri-pkl-config-java-ConverterFactory}[`ConverterFactory`].
+
Example: `ConverterFactories.pCollectionToCollection` converts any `pkl.base#Collection` to any implementation of `java.util.Collection<E>`, for any `E`.
+
Converter factories are called once per combination of source type and (possibly parameterized) target type.
The returned `Converter`s are cached.
. Create a `ValueMapperBuilder`, add all desired conversions, and build a `ValueMapper`.
. Either use the `ValueMapper` directly, or connect it to a `ConfigEvaluator` through `ConfigEvaluatorBuilder`.
== Further Information
Refer to the Javadoc and sources published with the library, or browse the library's {uri-pkl-config-java-main-sources}[main] and {uri-pkl-config-java-test-sources}[test] sources.

View File

@@ -0,0 +1,23 @@
.--indent
[%collapsible]
====
Default: `" "` (two spaces) +
Example: `"\t"` (one tab) +
The characters to use for indenting generated source code.
====
.-o, --output-dir
[%collapsible]
====
Default: (not set) +
Example: `generated/` +
The directory where generated source code is placed.
Relative paths are resolved against the working directory.
====
.--generate-spring-boot
[%collapsible]
====
Default: (not set) +
Flag that indicates to generate config classes for use with Spring Boot.
====