Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions LICENSE
Original file line number Diff line number Diff line change
Expand Up @@ -209,3 +209,4 @@ compare/swap/copy and absolute read/write methods in java/fury-core/src/main/jav
writeVarInt/writeVarLong in java/fury-core/src/main/java/io/fury/memory/MemoryBuffer.java is modified from https://github.com/EsotericSoftware/kryo/blob/master/src/com/esotericsoftware/kryo/unsafe/UnsafeOutput.java
java/fury-core/src/main/java/io/fury/util/{FuryObjectMap/ObjectIntMap/IdentityMap/IdentityObjectIntMap/LongMap}.java are adapted from https://github.com/EsotericSoftware/kryo/blob/master/src/com/esotericsoftware/kryo/util/{ObjectMap/ObjectIntMap/IdentityMap/IdentityObjectIntMap/IntMap}.java
{ParentClassLoader/ChildFirstURLClassLoader} in java/fury-core/src/main/java/io/fury/util/ClassLoaderUtils.java is copied from https://github.com/apache/spark/blob/master/core/src/main/java/org/apache/spark/util/{ParentClassLoader/ChildFirstURLClassLoader}.java
java/fury-core/src/main/java/io/fury/type/Generics.java id modified from https://github.com/EsotericSoftware/kryo/blob/master/src/com/esotericsoftware/kryo/util/DefaultGenerics.java
31 changes: 30 additions & 1 deletion java/fury-core/src/main/java/io/fury/Fury.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@

package io.fury;

import io.fury.memory.MemoryBuffer;
import io.fury.resolver.ClassInfo;
import io.fury.type.Type;
import io.fury.util.LoggerFactory;
import javax.annotation.concurrent.NotThreadSafe;
Expand Down Expand Up @@ -51,12 +53,17 @@ public final class Fury {

private final boolean referenceTracking;
private final Language language;
private int depth;

public Fury() {
public Fury(FuryBuilder builder) {
referenceTracking = false;
language = null;
}

public void writeReferencableToJava(MemoryBuffer buffer, Object obj, ClassInfo classInfo) {
throw new UnsupportedOperationException();
}

public Language getLanguage() {
return language;
}
Expand All @@ -68,4 +75,26 @@ public boolean trackingReference() {
public boolean isBasicTypesReferenceIgnored() {
return false;
}

public int getDepth() {
return depth;
}

public void setDepth(int depth) {
this.depth = depth;
}

public static FuryBuilder builder() {
return new FuryBuilder();
}

public static final class FuryBuilder {
public Fury build() {
return new Fury(this);
}

public FuryBuilder withLanguage(Language language) {
return this;
}
}
}
21 changes: 21 additions & 0 deletions java/fury-core/src/main/java/io/fury/resolver/ClassInfo.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
/*
* Copyright 2023 The Fury authors
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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
*
* http://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 io.fury.resolver;

public class ClassInfo {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/*
* Copyright 2023 The Fury authors
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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
*
* http://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 io.fury.resolver;

import io.fury.serializer.Serializer;

@SuppressWarnings({"rawtypes", "unchecked", "UnstableApiUsage"})
public class ClassResolver {

/** Get or create serializer for <code>cls</code>. */
@SuppressWarnings("unchecked")
public <T> Serializer<T> getSerializer(Class<T> cls) {
throw new UnsupportedOperationException();
}
}
208 changes: 208 additions & 0 deletions java/fury-core/src/main/java/io/fury/type/GenericType.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,208 @@
/*
* Copyright 2023 The Fury authors
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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
*
* http://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 io.fury.type;

import static io.fury.type.TypeUtils.getRawType;

import com.google.common.reflect.TypeToken;
import io.fury.resolver.ClassResolver;
import io.fury.serializer.Serializer;
import java.lang.reflect.GenericArrayType;
import java.lang.reflect.Modifier;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
import java.lang.reflect.WildcardType;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Predicate;

/**
* GenericType for building java generics as a tree and binding with fury serializers.
*
* @author chaokunyang
*/
// TODO(chaokunyang) refine generics which can be inspired by spring ResolvableType.
@SuppressWarnings("UnstableApiUsage")
public class GenericType {
static final Predicate<Type> defaultFinalPredicate =
type -> {
if (type.getClass() == Class.class) {
return Modifier.isFinal(((Class<?>) type).getModifiers());
} else {
return Modifier.isFinal((getRawType(type)).getModifiers());
}
};

final TypeToken<?> typeToken;
final Class<?> cls;
final GenericType[] typeParameters;
final int typeParametersCount;
final GenericType typeParameter0;
final GenericType typeParameter1;
final boolean hasGenericParameters;
final boolean isFinal;
// Used to cache serializer for final class to avoid hash lookup for serializer.
Serializer<?> serializer;

public GenericType(TypeToken<?> typeToken, boolean isFinal, GenericType... typeParameters) {
this.typeToken = typeToken;
this.cls = getRawType(typeToken);
this.typeParameters = typeParameters;
typeParametersCount = typeParameters.length;
hasGenericParameters = typeParameters.length > 0;
this.isFinal = isFinal;
if (typeParameters.length > 0) {
typeParameter0 = typeParameters[0];
} else {
typeParameter0 = null;
}
if (typeParameters.length > 1) {
typeParameter1 = typeParameters[1];
} else {
typeParameter1 = null;
}
}

/**
* Build generics based on an {@code context} which capture generic type information.
*
* <pre>{@code
* class A<T> {
* List<String> f1;
* List<T> f2;
* List<T>[] f3;
* T[] f4;
* SomeClass<T> f5;
* Map<T, List<SomeClass<T>>> f6;
* Map f7;
* }
*
* class B extends A<Long> {}
* }</pre>
*/
public static GenericType build(TypeToken<?> context, Type type) {
return build(context, type, defaultFinalPredicate);
}

public static GenericType build(TypeToken<?> context, Type type, Predicate<Type> finalPredicate) {
return build(context.resolveType(type).getType(), finalPredicate);
}

public static GenericType build(Class<?> context, Type type) {
return build(context, type, defaultFinalPredicate);
}

public static GenericType build(Class<?> context, Type type, Predicate<Type> finalPredicate) {
return build(TypeToken.of(context), type, finalPredicate);
}

public static GenericType build(Type type) {
return build(type, defaultFinalPredicate);
}

@SuppressWarnings("rawtypes")
public static GenericType build(Type type, Predicate<Type> finalPredicate) {
if (type instanceof ParameterizedType) {
// List<String>, List<T>, Map<String, List<String>>, SomeClass<T>
Type[] actualTypeArguments = ((ParameterizedType) type).getActualTypeArguments();
List<GenericType> list = new ArrayList<>();
for (Type t : actualTypeArguments) {
GenericType build = GenericType.build(t, finalPredicate);
list.add(build);
}
GenericType[] genericTypes = list.toArray(new GenericType[0]);
return new GenericType(TypeToken.of(type), finalPredicate.test(type), genericTypes);
} else if (type instanceof GenericArrayType) { // List<String>[] or T[]
Type componentType = ((GenericArrayType) type).getGenericComponentType();
return new GenericType(TypeToken.of(type), finalPredicate.test(type), build(componentType));
} else if (type instanceof TypeVariable) { // T
TypeVariable typeVariable = (TypeVariable) type;
Type typeVariableBound =
typeVariable.getBounds()[0]; // Bound 0 are a class, other bounds are interface.
return new GenericType(TypeToken.of(typeVariableBound), finalPredicate.test(type));
} else if (type instanceof WildcardType) {
// WildcardType: `T extends Number`, not a type, just an expression.
// `? extends java.util.Collection<? extends java.util.Collection<java.lang.Integer>>`
Type upperBound = ((WildcardType) type).getUpperBounds()[0];
if (upperBound instanceof ParameterizedType) {
return build(upperBound);
} else {
return new GenericType(TypeToken.of(upperBound), finalPredicate.test(type));
}
} else {
// Class type: String, Integer
return new GenericType(TypeToken.of(type), finalPredicate.test(type));
}
}

public TypeToken<?> getTypeToken() {
return typeToken;
}

public Class<?> getCls() {
return cls;
}

public GenericType[] getTypeParameters() {
return typeParameters;
}

public int getTypeParametersCount() {
return typeParametersCount;
}

public GenericType getTypeParameter0() {
return typeParameter0;
}

public GenericType getTypeParameter1() {
return typeParameter1;
}

public Serializer<?> getSerializer(ClassResolver classResolver) {
Serializer<?> serializer = this.serializer;
if (serializer == null) {
serializer = classResolver.getSerializer(cls);
this.serializer = serializer;
}
return serializer;
}

public boolean isFinal() {
return isFinal;
}

public Serializer<?> getSerializerOrNull(ClassResolver classResolver) {
if (isFinal) {
return getSerializer(classResolver);
} else {
return null;
}
}

public boolean hasGenericParameters() {
return hasGenericParameters;
}

@Override
public String toString() {
return "GenericType{" + typeToken.toString() + '}';
}
}
Loading