Skip to content

Commit

Permalink
build(kotlin): Add spotless ktfmt and enable explicit api mode for li…
Browse files Browse the repository at this point in the history
…brary code. (#1912)


## What does this PR do?

This PR modifies the build to:
1) add ktfmt - Since the fury java uses GOOGLE style, the fury kotlin
will also use GOOGLE style. The version of ktfmt used is the highest
compatible with the spotless maven plugin.
2) explicit api mode
3) parameterized kotlin version in pom.xml so it is easy to change in
future
4) Update README.md with build, format and testing instructions.

## Related issues

Closes #1896 

## Does this PR introduce any user-facing change?
None.

## Benchmark
N/A
  • Loading branch information
wywen authored Oct 26, 2024
1 parent a45886e commit 86d1201
Show file tree
Hide file tree
Showing 17 changed files with 1,238 additions and 1,320 deletions.
19 changes: 19 additions & 0 deletions kotlin/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,3 +35,22 @@ Additional support is added for the following classes in kotlin:
Additional Notes:

- wrappers classes created from `withDefault` method is currently not supported.

## Building Fury Kotlin

```bash
mvn clean
mvn -T10 compile
```

## Code Format

```bash
mvn -T10 spotless:apply
```

## Testing

```bash
mvn -T10 test
```
38 changes: 32 additions & 6 deletions kotlin/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,12 @@
<modelVersion>4.0.0</modelVersion>

<properties>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<kotlin.code.style>official</kotlin.code.style>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<kotlin.compiler.jvmTarget>1.8</kotlin.compiler.jvmTarget>
<maven-spotless-plugin.version>2.43.0</maven-spotless-plugin.version>
<kotlin.version>2.0.20</kotlin.version>
</properties>

<build>
Expand Down Expand Up @@ -136,6 +137,9 @@
<sourceDir>${project.basedir}/src/main/kotlin</sourceDir>
<sourceDir>${project.basedir}/src/main/java</sourceDir>
</sourceDirs>
<args>
<arg>-Xexplicit-api=strict</arg> <!-- Enable explicit api mode -->
</args>
</configuration>
</execution>
<execution>
Expand All @@ -148,6 +152,8 @@
<sourceDirs>
<sourceDir>${project.basedir}/src/test/kotlin</sourceDir>
</sourceDirs>
<args>
</args>
</configuration>
</execution>
</executions>
Expand All @@ -168,6 +174,26 @@
<target>8</target>
</configuration>
</plugin>
<plugin>
<groupId>com.diffplug.spotless</groupId>
<artifactId>spotless-maven-plugin</artifactId>
<version>${maven-spotless-plugin.version}</version>
<configuration>
<java>
<googleJavaFormat>
<!-- 1.19.1 support JDK21 -->
<version>1.19.1</version>
<style>GOOGLE</style>
</googleJavaFormat>
</java>
<kotlin>
<ktfmt>
<version>0.46</version>
<style>GOOGLE</style>
</ktfmt>
</kotlin>
</configuration>
</plugin>
</plugins>
</build>

Expand All @@ -180,13 +206,13 @@
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-test-testng</artifactId>
<version>2.0.20</version>
<version>${kotlin.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-stdlib</artifactId>
<version>2.0.20</version>
<version>${kotlin.version}</version>
</dependency>
</dependencies>
</project>
Original file line number Diff line number Diff line change
Expand Up @@ -20,127 +20,128 @@
package org.apache.fury.serializer.kotlin;

import kotlin.*;
import kotlin.UByteArray;
import kotlin.UIntArray;
import kotlin.ULongArray;
import kotlin.UShortArray;
import kotlin.text.*;
import kotlin.time.Duration;
import kotlin.time.DurationUnit;
import kotlin.time.TestTimeSource;
import kotlin.time.TimedValue;
import kotlin.uuid.Uuid;
import kotlin.UByteArray;
import kotlin.UIntArray;
import kotlin.ULongArray;
import kotlin.UShortArray;
import org.apache.fury.AbstractThreadSafeFury;
import org.apache.fury.Fury;
import org.apache.fury.ThreadSafeFury;
import org.apache.fury.resolver.ClassResolver;
import org.apache.fury.serializer.collection.CollectionSerializers;
import org.apache.fury.serializer.collection.MapSerializers;

/**
* KotlinSerializers provide default serializers for kotlin.
*/
/** KotlinSerializers provide default serializers for kotlin. */
@SuppressWarnings({"rawtypes", "unchecked"})
public class KotlinSerializers {

public static void registerSerializers(ThreadSafeFury fury) {
AbstractThreadSafeFury threadSafeFury = (AbstractThreadSafeFury) fury;
threadSafeFury.registerCallback(KotlinSerializers::registerSerializers);
}

public static void registerSerializers(Fury fury) {
ClassResolver resolver = fury.getClassResolver();

// UByte
Class ubyteClass = KotlinToJavaClass.INSTANCE.getUByteClass();
resolver.register(ubyteClass);
resolver.registerSerializer(ubyteClass, new UByteSerializer(fury));

// UShort
Class ushortClass = KotlinToJavaClass.INSTANCE.getUShortClass();
resolver.register(ushortClass);
resolver.registerSerializer(ushortClass, new UShortSerializer(fury));

// UInt
Class uintClass = KotlinToJavaClass.INSTANCE.getUIntClass();
resolver.register(uintClass);
resolver.registerSerializer(uintClass, new UIntSerializer(fury));

// ULong
Class ulongClass = KotlinToJavaClass.INSTANCE.getULongClass();
resolver.register(ulongClass);
resolver.registerSerializer(ulongClass, new ULongSerializer(fury));

// EmptyList
Class emptyListClass = KotlinToJavaClass.INSTANCE.getEmptyListClass();
resolver.register(emptyListClass);
resolver.registerSerializer(emptyListClass, new CollectionSerializers.EmptyListSerializer(fury, emptyListClass));

// EmptySet
Class emptySetClass = KotlinToJavaClass.INSTANCE.getEmptySetClass();
resolver.register(emptySetClass);
resolver.registerSerializer(emptySetClass, new CollectionSerializers.EmptySetSerializer(fury, emptySetClass));

// EmptyMap
Class emptyMapClass = KotlinToJavaClass.INSTANCE.getEmptyMapClass();
resolver.register(emptyMapClass);
resolver.registerSerializer(emptyMapClass, new MapSerializers.EmptyMapSerializer(fury, emptyMapClass));

// Non-Java collection implementation in kotlin stdlib.
Class arrayDequeClass = KotlinToJavaClass.INSTANCE.getArrayDequeClass();
resolver.register(arrayDequeClass);
resolver.registerSerializer(arrayDequeClass, new KotlinArrayDequeSerializer(fury, arrayDequeClass));

// Unsigned array classes: UByteArray, UShortArray, UIntArray, ULongArray.
resolver.register(UByteArray.class);
resolver.registerSerializer(UByteArray.class, new UByteArraySerializer(fury));
resolver.register(UShortArray.class);
resolver.registerSerializer(UShortArray.class, new UShortArraySerializer(fury));
resolver.register(UIntArray.class);
resolver.registerSerializer(UIntArray.class, new UIntArraySerializer(fury));
resolver.register(ULongArray.class);
resolver.registerSerializer(ULongArray.class, new ULongArraySerializer(fury));

// Ranges and Progressions.
resolver.register(kotlin.ranges.CharRange.class);
resolver.register(kotlin.ranges.CharProgression.class);
resolver.register(kotlin.ranges.IntRange.class);
resolver.register(kotlin.ranges.IntProgression.class);
resolver.register(kotlin.ranges.LongRange.class);
resolver.register(kotlin.ranges.LongProgression.class);
resolver.register(kotlin.ranges.UIntRange.class);
resolver.register(kotlin.ranges.UIntProgression.class);
resolver.register(kotlin.ranges.ULongRange.class);
resolver.register(kotlin.ranges.ULongProgression.class);

// Built-in classes.
resolver.register(kotlin.Pair.class);
resolver.register(kotlin.Triple.class);
resolver.register(kotlin.Result.class);
resolver.register(Result.Failure.class);

// kotlin.random
resolver.register(KotlinToJavaClass.INSTANCE.getRandomDefaultClass());
resolver.register(KotlinToJavaClass.INSTANCE.getRandomInternalClass());
resolver.register(KotlinToJavaClass.INSTANCE.getRandomSerializedClass());

// kotlin.text
resolver.register(Regex.class);
resolver.register(KotlinToJavaClass.INSTANCE.getRegexSerializedClass());
resolver.register(RegexOption.class);
resolver.register(CharCategory.class);
resolver.register(CharDirectionality.class);
resolver.register(HexFormat.class);
resolver.register(MatchGroup.class);

// kotlin.time
resolver.register(DurationUnit.class);
resolver.register(Duration.class);
resolver.registerSerializer(Duration.class, new DurationSerializer(fury));
resolver.register(TimedValue.class);

// kotlin.uuid
resolver.register(Uuid.class);
resolver.registerSerializer(Uuid.class, new UuidSerializer(fury));
}
public static void registerSerializers(ThreadSafeFury fury) {
AbstractThreadSafeFury threadSafeFury = (AbstractThreadSafeFury) fury;
threadSafeFury.registerCallback(KotlinSerializers::registerSerializers);
}

public static void registerSerializers(Fury fury) {
ClassResolver resolver = fury.getClassResolver();

// UByte
Class ubyteClass = KotlinToJavaClass.INSTANCE.getUByteClass();
resolver.register(ubyteClass);
resolver.registerSerializer(ubyteClass, new UByteSerializer(fury));

// UShort
Class ushortClass = KotlinToJavaClass.INSTANCE.getUShortClass();
resolver.register(ushortClass);
resolver.registerSerializer(ushortClass, new UShortSerializer(fury));

// UInt
Class uintClass = KotlinToJavaClass.INSTANCE.getUIntClass();
resolver.register(uintClass);
resolver.registerSerializer(uintClass, new UIntSerializer(fury));

// ULong
Class ulongClass = KotlinToJavaClass.INSTANCE.getULongClass();
resolver.register(ulongClass);
resolver.registerSerializer(ulongClass, new ULongSerializer(fury));

// EmptyList
Class emptyListClass = KotlinToJavaClass.INSTANCE.getEmptyListClass();
resolver.register(emptyListClass);
resolver.registerSerializer(
emptyListClass, new CollectionSerializers.EmptyListSerializer(fury, emptyListClass));

// EmptySet
Class emptySetClass = KotlinToJavaClass.INSTANCE.getEmptySetClass();
resolver.register(emptySetClass);
resolver.registerSerializer(
emptySetClass, new CollectionSerializers.EmptySetSerializer(fury, emptySetClass));

// EmptyMap
Class emptyMapClass = KotlinToJavaClass.INSTANCE.getEmptyMapClass();
resolver.register(emptyMapClass);
resolver.registerSerializer(
emptyMapClass, new MapSerializers.EmptyMapSerializer(fury, emptyMapClass));

// Non-Java collection implementation in kotlin stdlib.
Class arrayDequeClass = KotlinToJavaClass.INSTANCE.getArrayDequeClass();
resolver.register(arrayDequeClass);
resolver.registerSerializer(
arrayDequeClass, new KotlinArrayDequeSerializer(fury, arrayDequeClass));

// Unsigned array classes: UByteArray, UShortArray, UIntArray, ULongArray.
resolver.register(UByteArray.class);
resolver.registerSerializer(UByteArray.class, new UByteArraySerializer(fury));
resolver.register(UShortArray.class);
resolver.registerSerializer(UShortArray.class, new UShortArraySerializer(fury));
resolver.register(UIntArray.class);
resolver.registerSerializer(UIntArray.class, new UIntArraySerializer(fury));
resolver.register(ULongArray.class);
resolver.registerSerializer(ULongArray.class, new ULongArraySerializer(fury));

// Ranges and Progressions.
resolver.register(kotlin.ranges.CharRange.class);
resolver.register(kotlin.ranges.CharProgression.class);
resolver.register(kotlin.ranges.IntRange.class);
resolver.register(kotlin.ranges.IntProgression.class);
resolver.register(kotlin.ranges.LongRange.class);
resolver.register(kotlin.ranges.LongProgression.class);
resolver.register(kotlin.ranges.UIntRange.class);
resolver.register(kotlin.ranges.UIntProgression.class);
resolver.register(kotlin.ranges.ULongRange.class);
resolver.register(kotlin.ranges.ULongProgression.class);

// Built-in classes.
resolver.register(kotlin.Pair.class);
resolver.register(kotlin.Triple.class);
resolver.register(kotlin.Result.class);
resolver.register(Result.Failure.class);

// kotlin.random
resolver.register(KotlinToJavaClass.INSTANCE.getRandomDefaultClass());
resolver.register(KotlinToJavaClass.INSTANCE.getRandomInternalClass());
resolver.register(KotlinToJavaClass.INSTANCE.getRandomSerializedClass());

// kotlin.text
resolver.register(Regex.class);
resolver.register(KotlinToJavaClass.INSTANCE.getRegexSerializedClass());
resolver.register(RegexOption.class);
resolver.register(CharCategory.class);
resolver.register(CharDirectionality.class);
resolver.register(HexFormat.class);
resolver.register(MatchGroup.class);

// kotlin.time
resolver.register(DurationUnit.class);
resolver.register(Duration.class);
resolver.registerSerializer(Duration.class, new DurationSerializer(fury));
resolver.register(TimedValue.class);

// kotlin.uuid
resolver.register(Uuid.class);
resolver.registerSerializer(Uuid.class, new UuidSerializer(fury));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,29 +22,26 @@ package org.apache.fury.serializer.kotlin
/**
* Collection builder interface adapts an iterable to allow incremental build by the fury protocol.
*/
interface CollectionBuilder <E, T: Iterable<E>> {
fun add(element: E): Boolean
fun result(): T
public interface CollectionBuilder<E, T : Iterable<E>> {
public fun add(element: E): Boolean

public fun result(): T
}

/**
* Abstract builder for [kotlin.collections.List] interface.
*/
abstract class AbstractListBuilder<E, T:List<E>>
: CollectionBuilder<E, T>, AdaptedCollection<E>() {
protected open val builder: MutableList<E> = mutableListOf()
override val size: Int
get() = builder.size
override fun add(element: E) =
builder.add(element)
override fun iterator(): MutableIterator<E> = builder.iterator()
/** Abstract builder for [kotlin.collections.List] interface. */
public abstract class AbstractListBuilder<E, T : List<E>> :
CollectionBuilder<E, T>, AdaptedCollection<E>() {
protected open val builder: MutableList<E> = mutableListOf()
override val size: Int
get() = builder.size

override fun add(element: E): Boolean = builder.add(element)

override fun iterator(): MutableIterator<E> = builder.iterator()
}

/**
* Builder for [kotlin.collections.ArrayDeque].
*/
class ArrayDequeBuilder<E>(
override val builder: ArrayDeque<E>
): AbstractListBuilder<E, ArrayDeque<E>>() {
override fun result(): ArrayDeque<E> = builder
/** Builder for [kotlin.collections.ArrayDeque]. */
public class ArrayDequeBuilder<E>(override val builder: ArrayDeque<E>) :
AbstractListBuilder<E, ArrayDeque<E>>() {
override fun result(): ArrayDeque<E> = builder
}
Loading

0 comments on commit 86d1201

Please sign in to comment.