You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ignite.apache.org by am...@apache.org on 2020/12/15 14:09:52 UTC
[ignite-3] 03/03: WIP.
This is an automated email from the ASF dual-hosted git repository.
amashenkov pushed a commit to branch ignite-13618-javapoet
in repository https://gitbox.apache.org/repos/asf/ignite-3.git
commit c688848462841423ba6102188e6eeb88eb6881fd
Author: Andrew Mashenkov <an...@gmail.com>
AuthorDate: Tue Dec 15 17:09:29 2020 +0300
WIP.
---
.../apache/ignite/internal/schema/NativeType.java | 8 +
.../internal/schema/marshaller/MarshallerUtil.java | 239 ++++++++++-
.../generator/FieldAccessExprGenerator.java | 360 ----------------
.../IdentityObjectMarshallerExprGenerator.java | 35 +-
.../generator/JaninoSerializerGenerator.java | 451 +++++----------------
.../generator/MarshallerExprGenerator.java | 114 +++---
.../marshaller/generator/TupleAccessorExpr.java | 134 +++---
.../benchmarks/SerializerBenchmarkTest.java | 43 +-
.../schema/marshaller/JavaSerializerTest.java | 88 +++-
9 files changed, 612 insertions(+), 860 deletions(-)
diff --git a/modules/commons/src/main/java/org/apache/ignite/internal/schema/NativeType.java b/modules/commons/src/main/java/org/apache/ignite/internal/schema/NativeType.java
index 211a1e1..e5d40c7 100644
--- a/modules/commons/src/main/java/org/apache/ignite/internal/schema/NativeType.java
+++ b/modules/commons/src/main/java/org/apache/ignite/internal/schema/NativeType.java
@@ -133,4 +133,12 @@ public class NativeType implements Comparable<NativeType> {
return typeSpec.name().compareTo(o.typeSpec.name());
}
+
+ /** {@inheritDoc} */
+ @Override public String toString() {
+ return "NativeType{" +
+ "typeSpec=" + typeSpec +
+ ", len=" + len +
+ '}';
+ }
}
diff --git a/modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/MarshallerUtil.java b/modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/MarshallerUtil.java
index f43f9b5..d799ad8 100644
--- a/modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/MarshallerUtil.java
+++ b/modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/MarshallerUtil.java
@@ -17,11 +17,40 @@
package org.apache.ignite.internal.schema.marshaller;
+import com.squareup.javapoet.JavaFile;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.URI;
+import java.net.URL;
+import java.net.URLClassLoader;
import java.util.BitSet;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.NoSuchElementException;
+import java.util.Set;
import java.util.UUID;
+import javax.tools.Diagnostic;
+import javax.tools.DiagnosticCollector;
+import javax.tools.FileObject;
+import javax.tools.ForwardingJavaFileManager;
+import javax.tools.JavaCompiler;
+import javax.tools.JavaFileManager;
+import javax.tools.JavaFileObject;
+import javax.tools.SimpleJavaFileObject;
+import javax.tools.StandardLocation;
+import javax.tools.ToolProvider;
import org.apache.ignite.internal.schema.NativeType;
import org.apache.ignite.internal.schema.TupleAssembler;
import org.apache.ignite.internal.util.ObjectFactory;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import static javax.tools.StandardLocation.CLASS_PATH;
/**
* Marshaller utility class.
@@ -97,7 +126,7 @@ public final class MarshallerUtil {
return null;
}
- public static <T> ObjectFactory<T> factoryForClass(Class<T> type) {
+ public static <T> ObjectFactory<T> factoryForClass(Class<T> type) {
if (mode(type) == null)
return new ObjectFactory<>(type);
else
@@ -109,4 +138,212 @@ public final class MarshallerUtil {
*/
private MarshallerUtil() {
}
+
+ public static ClassLoader compileCode(JavaFile javafile) {
+ return compileCode(javafile, null);
+ }
+
+ public static ClassLoader compileCode(JavaFile javafile, Map<String, byte[]> classes) {
+ final JavaCompiler cmp = ToolProvider.getSystemJavaCompiler();
+
+ final Map<String, byte[]> classes0 = classes == null ? new HashMap<>() : classes;
+
+ try (final MemoryJavaFileManager fileManager = new MemoryJavaFileManager(cmp.getStandardFileManager(null, null, null), classes0)) {
+ DiagnosticCollector<JavaFileObject> diagnostics = new DiagnosticCollector<>();
+
+ JavaCompiler.CompilationTask task = cmp.getTask(null, fileManager, diagnostics, null, null, Collections.singletonList(javafile.toJavaFileObject()));
+
+ final MemoryClassLoader loader = new MemoryClassLoader(fileManager.getClasses(), ClassLoader.getSystemClassLoader());
+
+ if (task.call())
+ return loader;
+
+ // TODO: write to log.
+ for (Diagnostic diagnostic : diagnostics.getDiagnostics()) {
+ System.out.println(diagnostic.getCode());
+ System.out.println(diagnostic.getKind());
+ System.out.println(diagnostic.getPosition());
+ System.out.println(diagnostic.getStartPosition());
+ System.out.println(diagnostic.getEndPosition());
+ System.out.println(diagnostic.getSource());
+ System.out.println(diagnostic.getMessage(null));
+ }
+
+ throw new IllegalStateException("Failed to compile code:\n" + javafile.toString());
+ }
+ catch (IOException ex) {
+ throw new IllegalStateException("Failed to compile code.", ex);
+ }
+ }
+
+ private static class MemoryJavaFileManager extends ForwardingJavaFileManager<JavaFileManager> {
+ private final Map<String, byte[]> classes;
+
+ public MemoryJavaFileManager(JavaFileManager fileManager, Map<String, byte[]> classes) {
+ super(fileManager);
+
+ this.classes = classes;
+ }
+
+ Map<String, byte[]> getClasses() {
+ return classes;
+ }
+
+ /**
+ * A file object that stores Java bytecode into the classBytes map.
+ */
+ private class ClassOutputBuffer extends SimpleJavaFileObject {
+ private final String classname;
+
+ ClassOutputBuffer(String classname) {
+ super(URI.create(classname), Kind.CLASS);
+ this.classname = classname;
+ }
+
+ @Override public OutputStream openOutputStream() {
+ return new ByteArrayOutputStream() {
+ @Override public void close() throws IOException {
+ super.close();
+
+ classes.put(classname, toByteArray());
+ }
+ };
+ }
+ }
+
+ @Override public ClassLoader getClassLoader(Location location) {
+ return new MemoryClassLoader(classes, super.getClassLoader(location));
+ }
+ /*
+ @Override
+ public Iterable<JavaFileObject> list(Location location, String packageName, Set<JavaFileObject.Kind> kinds,
+ boolean recurse) throws IOException {
+ final Iterable<JavaFileObject> it = super.list(location, packageName, kinds, recurse);
+
+ if (location == CLASS_PATH) {
+ assert kinds.contains(JavaFileObject.Kind.CLASS);
+
+ Iterable<JavaFileObject> localClasses = new Iterable<>() {
+ @NotNull @Override public Iterator<JavaFileObject> iterator() {
+ return classes.keySet().stream().map(cn -> getJavaFileObjectByName(cn)).iterator();
+ }
+ };
+
+ return concat(localClasses, it);
+ }
+ else
+ return it;
+ }*/
+
+
+ @Override public boolean contains(Location location, FileObject fo) throws IOException {
+ return super.contains(location, fo);
+ }
+
+ @Override public JavaFileObject getJavaFileForInput(Location location, String className,
+ JavaFileObject.Kind kind) throws IOException {
+ if (location == StandardLocation.CLASS_OUTPUT) {
+ JavaFileObject javaFileObject = getJavaFileObjectByName(className);
+
+ if (javaFileObject != null)
+ return javaFileObject;
+ }
+
+ return fileManager.getJavaFileForInput(location, className, kind);
+ }
+
+ @Nullable private JavaFileObject getJavaFileObjectByName(String className) {
+ final byte[] bytes = classes.get(className);
+
+ if (bytes != null) {
+ return new SimpleJavaFileObject(URI.create(className), JavaFileObject.Kind.OTHER) {
+ @Override public InputStream openInputStream() {
+ return new ByteArrayInputStream(bytes);
+ }
+ };
+ }
+ return null;
+ }
+
+ @Override public JavaFileObject getJavaFileForOutput(Location location,
+ String className,
+ JavaFileObject.Kind kind,
+ FileObject sibling) throws IOException {
+ if (kind == JavaFileObject.Kind.CLASS)
+ return new ClassOutputBuffer(className);
+ else
+ return super.getJavaFileForOutput(location, className, kind, sibling);
+ }
+ }
+
+ private static final class MemoryClassLoader extends URLClassLoader {
+ private static final URL[] EMPTY_URLS = new URL[0];
+
+ private final Map<String, byte[]> classBytes;
+
+ public MemoryClassLoader(Map<String, byte[]> classBytes, ClassLoader parent) {
+ super(EMPTY_URLS, parent);
+
+ this.classBytes = classBytes;
+ }
+
+ @Override protected Class<?> findClass(String className) throws ClassNotFoundException {
+ byte[] buf = classBytes.get(className); // clear the bytes in map -- we don't need it anymore
+
+ if (buf != null)
+ return defineClass(className, buf, 0, buf.length);
+ else
+ return super.findClass(className);
+ }
+
+ @Override public Class<?> loadClass(String name) throws ClassNotFoundException {
+ return super.loadClass(name);
+ }
+ }
+
+ public static <E> Iterable<E> concat(
+ Iterable<? extends E> i1,
+ Iterable<? extends E> i2) {
+ return new Iterable<E>() {
+ @Override public Iterator<E> iterator() {
+ return new Iterator<E>() {
+ Iterator<? extends E> listIterator = i1.iterator();
+ Boolean checkedHasNext;
+ E nextValue;
+ private boolean startTheSecond;
+
+ void theNext() {
+ if (listIterator.hasNext()) {
+ checkedHasNext = true;
+ nextValue = listIterator.next();
+ }
+ else if (startTheSecond)
+ checkedHasNext = false;
+ else {
+ startTheSecond = true;
+ listIterator = i2.iterator();
+ theNext();
+ }
+ }
+
+ @Override public boolean hasNext() {
+ if (checkedHasNext == null)
+ theNext();
+ return checkedHasNext;
+ }
+
+ @Override public E next() {
+ if (!hasNext())
+ throw new NoSuchElementException();
+ checkedHasNext = null;
+ return nextValue;
+ }
+
+ @Override public void remove() {
+ listIterator.remove();
+ }
+ };
+ }
+ };
+ }
}
diff --git a/modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/generator/FieldAccessExprGenerator.java b/modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/generator/FieldAccessExprGenerator.java
deleted file mode 100644
index fb3736a..0000000
--- a/modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/generator/FieldAccessExprGenerator.java
+++ /dev/null
@@ -1,360 +0,0 @@
-/*
- * 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 org.apache.ignite.internal.schema.marshaller.generator;
-
-import org.apache.ignite.internal.schema.marshaller.BinaryMode;
-import org.jetbrains.annotations.Nullable;
-
-import static org.apache.ignite.internal.schema.marshaller.generator.JaninoSerializerGenerator.LF;
-
-/**
- * Object field access expression generators.
- */
-class FieldAccessExprGenerator {
- /** Append null expression. */
- private static final String WRITE_NULL_EXPR = "asm.appendNull();";
-
- /**
- * Created object access expressions generator.
- *
- * @param mode Field access binary mode.
- * @param colIdx Column absolute index in schema.
- * @return Object field access expressions generator.
- */
- static FieldAccessExprGenerator createIdentityAccessor(BinaryMode mode, int colIdx) {
- return createAccessor(mode, colIdx, -1L);
- }
-
- /**
- * Created object field access expressions generator.
- *
- * @param mode Field access binary mode.
- * @param colIdx Column absolute index in schema.
- * @param offset Object field offset.
- * @return Object field access expressions generator.
- */
- static FieldAccessExprGenerator createAccessor(BinaryMode mode, int colIdx, long offset) {
- switch (mode) {
- case BYTE:
- return new FieldAccessExprGenerator(
- colIdx,
- "Byte",
- "tuple.byteValueBoxed",
- "asm.appendByte",
- offset);
-
- case P_BYTE:
- return new FieldAccessExprGenerator(
- colIdx,
- "tuple.byteValue",
- "asm.appendByte",
- offset,
- "IgniteUnsafeUtils.getByteField",
- "IgniteUnsafeUtils.putByteField"
- );
-
- case SHORT:
- return new FieldAccessExprGenerator(
- colIdx,
- "Short",
- "tuple.shortValueBoxed",
- "asm.appendShort",
- offset);
-
- case P_SHORT:
- return new FieldAccessExprGenerator(
- colIdx,
- "tuple.shortValue",
- "asm.appendShort",
- offset,
- "IgniteUnsafeUtils.getShortField",
- "IgniteUnsafeUtils.putShortField"
- );
-
- case INT:
- return new FieldAccessExprGenerator(
- colIdx,
- "Integer",
- "tuple.intValueBoxed",
- "asm.appendInt",
- offset);
-
- case P_INT:
- return new FieldAccessExprGenerator(
- colIdx,
- "tuple.intValue",
- "asm.appendInt",
- offset,
- "IgniteUnsafeUtils.getIntField",
- "IgniteUnsafeUtils.putIntField"
- );
-
- case LONG:
- return new FieldAccessExprGenerator(
- colIdx,
- "Long",
- "tuple.longValueBoxed",
- "asm.appendLong",
- offset);
-
- case P_LONG:
- return new FieldAccessExprGenerator(
- colIdx,
- "tuple.longValue",
- "asm.appendLong",
- offset,
- "IgniteUnsafeUtils.getLongField",
- "IgniteUnsafeUtils.putLongField"
- );
-
- case FLOAT:
- return new FieldAccessExprGenerator(
- colIdx,
- "Float",
- "tuple.floatValueBoxed",
- "asm.appendFloat",
- offset);
-
- case P_FLOAT:
- return new FieldAccessExprGenerator(
- colIdx,
- "tuple.floatValue",
- "asm.appendFloat",
- offset,
- "IgniteUnsafeUtils.getFloatField",
- "IgniteUnsafeUtils.putFloatField"
- );
-
- case DOUBLE:
- return new FieldAccessExprGenerator(
- colIdx,
- "Double",
- "tuple.doubleValueBoxed",
- "asm.appendDouble",
- offset);
-
- case P_DOUBLE:
- return new FieldAccessExprGenerator(
- colIdx,
- "tuple.doubleValue",
- "asm.appendDouble",
- offset,
- "IgniteUnsafeUtils.getDoubleField",
- "IgniteUnsafeUtils.putDoubleField"
- );
-
- case UUID:
- return new FieldAccessExprGenerator(
- colIdx,
- "UUID",
- "tuple.uuidValue", "asm.appendUuid",
- offset);
-
- case BITSET:
- return new FieldAccessExprGenerator(
- colIdx,
- "BitSet",
- "tuple.bitmaskValue", "asm.appendBitmask",
- offset);
-
- case STRING:
- return new FieldAccessExprGenerator(
- colIdx,
- "String",
- "tuple.stringValue", "asm.appendString",
- offset);
-
- case BYTE_ARR:
- return new FieldAccessExprGenerator(
- colIdx,
- "byte[]",
- "tuple.bytesValue", "asm.appendBytes",
- offset);
- default:
- throw new IllegalStateException("Unsupportd binary mode");
- }
- }
-
- /** Object field offset or {@code -1} for identity accessor. */
- private final long offset;
-
- /** Absolute schema index. */
- private final int colIdx;
-
- /** Class cast expression. */
- private final String classExpr;
-
- /** Write column value expression. */
- private final String writeColMethod;
-
- /** Read column value expression. */
- private final String readColMethod;
-
- /** Read object field expression. */
- private final String getFieldMethod;
-
- /** Write object field expression. */
- private final String putFieldMethod;
-
- /**
- * Constructor.
- *
- * @param colIdx Absolute schema index in schema.
- * @param castClassExpr Class cast expression
- * @param readColMethod Read column value expression.
- * @param writeColMethod Write column value expression.
- * @param offset Field offset or {@code -1} for identity accessor.
- */
- private FieldAccessExprGenerator(
- int colIdx,
- String castClassExpr,
- String readColMethod,
- String writeColMethod,
- long offset
- ) {
- this(colIdx, castClassExpr, readColMethod, writeColMethod, offset,
- "IgniteUnsafeUtils.getObjectField", "IgniteUnsafeUtils.putObjectField");
- }
-
- /**
- * Constructor.
- *
- * @param colIdx Absolute schema index in schema.
- * @param readColMethod Read column value expression.
- * @param writeColMethod Write column value expression.
- * @param offset Field offset or {@code -1} for identity accessor.
- * @param getFieldMethod Read object field expression.
- * @param putFieldMethod Read object field expression.
- */
- public FieldAccessExprGenerator(
- int colIdx,
- String readColMethod,
- String writeColMethod,
- long offset,
- String getFieldMethod,
- String putFieldMethod
- ) {
- this(colIdx, null /* primitive type */, readColMethod, writeColMethod, offset, getFieldMethod, putFieldMethod);
- }
-
- /**
- * Constructor.
- *
- * @param colIdx Absolute schema index in schema.
- * @param castClassExpr Class cast expression or {@code null} if not applicable.
- * @param readColMethod Read column value expression.
- * @param writeColMethod Write column value expression.
- * @param offset Field offset or {@code -1} for identity accessor.
- * @param getFieldMethod Read object field expression.
- * @param putFieldMethod Read object field expression.
- */
- private FieldAccessExprGenerator(
- int colIdx,
- @Nullable String castClassExpr,
- String readColMethod,
- String writeColMethod,
- long offset,
- String getFieldMethod,
- String putFieldMethod
- ) {
- this.offset = offset;
- this.colIdx = colIdx;
- this.classExpr = castClassExpr;
- this.putFieldMethod = putFieldMethod;
- this.getFieldMethod = getFieldMethod;
- this.writeColMethod = writeColMethod;
- this.readColMethod = readColMethod;
- }
-
- /**
- * @return {@code true} if it is primitive typed field accessor, {@code false} otherwise.
- */
- private boolean isPrimitive() {
- return classExpr == null;
- }
-
- /**
- * @return {@code true} if is identity accessor, {@code false} otherwise.
- */
- private boolean isIdentityAccessor() {
- return offset == -1;
- }
-
- /**
- * @return Object field value access expression or object value expression for simple types.
- */
- public String getFieldExpr() {
- if (isIdentityAccessor())
- return "obj"; // Identity accessor.
-
- return getFieldMethod + "(obj, " + offset + ')';
- }
-
- /**
- * Appends write value to field expression.
- *
- * @param sb String bulder.
- * @param valueExpression Value expression.
- * @param indent Line indentation.
- */
- public final void appendPutFieldExpr(StringBuilder sb, String valueExpression, String indent) {
- sb.append(indent).append(putFieldMethod).append("(obj, ").append(offset).append(", ").append(valueExpression).append(')');
- sb.append(";" + LF);
- }
-
- /**
- * Appends write value to column expression.
- *
- * @param sb String bulder.
- * @param valueExpr Value expression.
- * @param indent Line indentation.
- */
- public final void appendWriteColumnExpr(StringBuilder sb, String valueExpr, String indent) {
- if (isPrimitive() || isIdentityAccessor()) {
- // Translate to:
- // asm.appendX((T) %value%);
- // or for primitive value:
- // asm.appendX(%value%);
- sb.append(indent).append(writeColMethod).append('(');
-
- if (classExpr != null)
- sb.append("(").append(classExpr).append(")");
-
- sb.append(valueExpr).append(");" + LF);
-
- return;
- }
-
- assert classExpr != null;
-
- // Translate to:
- // { T fVal = (T)%value%;
- // if (fVal == null) asm.appendNull() else asm.appendX(fVal); }
- sb.append(indent).append("{ ").append(classExpr).append(" fVal = (").append(classExpr).append(')').append(valueExpr).append(";" + LF);
- sb.append(indent).append("if (fVal == null) " + WRITE_NULL_EXPR + LF);
- sb.append(indent).append("else ").append(writeColMethod).append("(fVal); }" + LF);
-
- }
-
- /**
- * @return Column value read expression.
- */
- public String readColumnExpr() {
- return readColMethod + "(" + colIdx + ")";
- }
-}
diff --git a/modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/generator/IdentityObjectMarshallerExprGenerator.java b/modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/generator/IdentityObjectMarshallerExprGenerator.java
index f86bc0b..9d292c7 100644
--- a/modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/generator/IdentityObjectMarshallerExprGenerator.java
+++ b/modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/generator/IdentityObjectMarshallerExprGenerator.java
@@ -18,6 +18,7 @@
package org.apache.ignite.internal.schema.marshaller.generator;
import com.squareup.javapoet.CodeBlock;
+import com.squareup.javapoet.TypeSpec;
import org.apache.ignite.internal.schema.marshaller.Serializer;
/**
@@ -27,37 +28,37 @@ class IdentityObjectMarshallerExprGenerator extends MarshallerExprGenerator {
/**
* Constructor.
*
- * @param accessor Object field access expression generators.
- * @param tupleAccessorGen
+ * @param aClass
+ * @param tupleAccessorGen Object field access expression generators.
*/
- IdentityObjectMarshallerExprGenerator(FieldAccessExprGenerator accessor,
- TupleAccessorExpr tupleAccessorGen) {
- super(
- null /* no instantiation needed */,
- new FieldAccessExprGenerator[] {accessor},
- new TupleAccessorExpr[] {tupleAccessorGen}
- );
-
+ IdentityObjectMarshallerExprGenerator(Class<?> aClass, TupleAccessorExpr tupleAccessorGen) {
+ super(aClass, null /* no instantiation needed */, new TupleAccessorExpr[] {tupleAccessorGen});
}
/** {@inheritDoc} */
- @Override public void appendMarshallObjectExpr(StringBuilder sb, String indent) {
- for (int i = 0; i < accessors.length; i++)
- accessors[i].appendWriteColumnExpr(sb, "obj", indent);
+ @Override boolean isSimpleType() {
+ return true;
}
/** {@inheritDoc} */
- @Override public void appendUnmarshallObjectExpr(StringBuilder sb, String indent) {
- sb.append(indent).append("Object obj = ").append(accessors[0].readColumnExpr()).append(";" + JaninoSerializerGenerator.LF);
- }
-
@Override public CodeBlock unmarshallObjectCode(String tupleExpr) {
return CodeBlock.builder()
.add("return ").addStatement(tupleAccessors[0].read(tupleExpr))
.build();
}
+ /** {@inheritDoc} */
@Override public CodeBlock marshallObjectCode(String asm, String objVar) {
return tupleAccessors[0].write(asm, objVar);
}
+
+ /** {@inheritDoc} */
+ @Override public CodeBlock getValueCode(String objVar, int colIdx) {
+ return CodeBlock.of(objVar);
+ }
+
+ /** {@inheritDoc} */
+ @Override public void staticHandlers(TypeSpec.Builder builder, CodeBlock.Builder staticBuilder) {
+
+ }
}
diff --git a/modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/generator/JaninoSerializerGenerator.java b/modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/generator/JaninoSerializerGenerator.java
index a45a8be..9de4011 100644
--- a/modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/generator/JaninoSerializerGenerator.java
+++ b/modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/generator/JaninoSerializerGenerator.java
@@ -24,15 +24,13 @@ import com.squareup.javapoet.JavaFile;
import com.squareup.javapoet.MethodSpec;
import com.squareup.javapoet.TypeName;
import com.squareup.javapoet.TypeSpec;
-import java.lang.invoke.VarHandle;
-import java.lang.reflect.Constructor;
-import java.lang.reflect.Field;
+import java.lang.invoke.MethodHandles;
+import java.lang.reflect.InvocationTargetException;
import java.util.HashMap;
+import java.util.Map;
import javax.annotation.processing.Generated;
import javax.lang.model.element.Modifier;
-import javax.tools.JavaCompiler;
import javax.tools.JavaFileManager;
-import javax.tools.ToolProvider;
import org.apache.ignite.internal.schema.ByteBufferTuple;
import org.apache.ignite.internal.schema.Columns;
import org.apache.ignite.internal.schema.SchemaDescriptor;
@@ -44,16 +42,9 @@ import org.apache.ignite.internal.schema.marshaller.SerializationException;
import org.apache.ignite.internal.schema.marshaller.Serializer;
import org.apache.ignite.internal.schema.marshaller.SerializerFactory;
import org.apache.ignite.internal.util.ObjectFactory;
-import org.codehaus.commons.compiler.IClassBodyEvaluator;
-import org.codehaus.janino.ClassLoaderIClassLoader;
-import org.codehaus.janino.Compiler;
-import org.codehaus.janino.util.ResourceFinderClassLoader;
-import org.codehaus.janino.util.resource.MapResourceCreator;
-import org.codehaus.janino.util.resource.MapResourceFinder;
-import org.codehaus.janino.util.resource.Resource;
-import org.codehaus.janino.util.resource.StringResource;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
+import org.jetbrains.annotations.TestOnly;
/**
* {@link Serializer} code generator backed with Janino.
@@ -64,17 +55,7 @@ public class JaninoSerializerGenerator implements SerializerFactory {
public static final String SERIALIZER_CLASS_NAME_PREFIX = "JaninoSerializerForSchema_";
- /** Tabulate. */
- static final String TAB = " ";
-
- /** Line feed. */
- static final char LF = '\n';
-
- /** String buffer initial size. */
- public static final int INITIAL_BUFFER_SIZE = 8 * 1024;
-
- /** Debug flag. */
- private static final boolean enabledDebug = true;
+ private Map<String, byte[]> classes;
/** {@inheritDoc} */
@Override public Serializer create(
@@ -85,52 +66,31 @@ public class JaninoSerializerGenerator implements SerializerFactory {
// Generate Serializer code.
final String className = SERIALIZER_CLASS_NAME_PREFIX + schema.version();
- String code = generateSerializerClassCode(className, schema, keyClass, valClass);
+ JavaFile javaFile = generateSerializerClassCode(className, schema, keyClass, valClass);
//TODO: pass code to logger on trace level.
+ System.out.println(javaFile.toString());
- final HashMap<String, byte[]> classes = new HashMap<>();
- final Compiler cmp = new Compiler(
- new MapResourceFinder(classes),
- new ClassLoaderIClassLoader(getClass().getClassLoader())
- );
-
- cmp.setClassFileCreator(new MapResourceCreator(classes));
-
- if (enabledDebug) {
- cmp.setDebugSource(true);
- cmp.setDebugLines(true);
- cmp.setDebugVars(true);
- cmp.setVerbose(true);
-
- System.out.print(code);
- }
-
- try { // Compile code.
- cmp.compile(new Resource[] {
- new StringResource("file", code)});
-
- ClassLoader cl = new ResourceFinderClassLoader(
- new MapResourceFinder(classes),
- getClass().getClassLoader()
- );
+ final ClassLoader loader = MarshallerUtil.compileCode(javaFile, classes);
- // Load class and create instance.
- final Class<?> aClass = cl.loadClass(SERIALIZER_PACKAGE_NAME + '.' + className);
+ try {
+ final Class<?> aClass = loader.loadClass(javaFile.packageName + '.' + className);
- final Constructor<Serializer> ctor = (Constructor<Serializer>)aClass
- .getDeclaredConstructor(schema.getClass(), Class.class, Class.class);
+ return (Serializer)aClass
+ .getDeclaredConstructor(SchemaDescriptor.class, Class.class, Class.class)
+ .newInstance(schema, keyClass, valClass);
- return ctor.newInstance(schema, keyClass, valClass);
}
- catch (Throwable ex) {
- if (enabledDebug)
- throw new IllegalStateException("Failed to compile generated Serializer code:\n" + code, ex);
- else
- throw new IllegalStateException("Failed to compile/instantiate generated Serializer.", ex);
+ catch (InstantiationException | ClassNotFoundException | NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
+ throw new IllegalStateException(e);
}
}
+ @TestOnly
+ public void setClasses(Map<String, byte[]> classes) {
+ this.classes = classes;
+ }
+
/**
* Generates serializer code.
*
@@ -138,50 +98,46 @@ public class JaninoSerializerGenerator implements SerializerFactory {
* @param valClass Value class.
* @return Generated class code.
*/
- private String generateSerializerClassCode(String className, SchemaDescriptor schema, Class<?> keyClass,
+ private JavaFile generateSerializerClassCode(String className, SchemaDescriptor schema, Class<?> keyClass,
Class<?> valClass) {
try {
- final StringBuilder sb = new StringBuilder();
-
// Build field accessor generators.
- final MarshallerExprGenerator keyMarsh = createObjectMarshaller(valClass, "valFactory", schema.valueColumns(), schema.keyColumns().length());
- final MarshallerExprGenerator valMarsh = createObjectMarshaller(valClass, "valFactory", schema.valueColumns(), schema.keyColumns().length());
-
- JavaFile
- .builder(
- SERIALIZER_PACKAGE_NAME,
- TypeSpec.classBuilder(className)
- .addSuperinterface(Serializer.class)
+ final MarshallerExprGenerator keyMarsh = createObjectMarshaller(keyClass, "keyFactory", schema.keyColumns(), 0);
+ final MarshallerExprGenerator valMarsh = createObjectMarshaller(valClass, "valFactory", schema.valueColumns(), schema.valueColumns().length());
+
+ final TypeSpec.Builder classBuilder = TypeSpec.classBuilder(className)
+ .addSuperinterface(Serializer.class)
+ .addModifiers(Modifier.PUBLIC)
+ .addAnnotation(AnnotationSpec.builder(Generated.class).addMember("value", "$S", getClass().getCanonicalName()).build());
+
+ initFieldHandlers(keyMarsh, valMarsh, classBuilder);
+
+ classBuilder.addField(SchemaDescriptor.class, "schema", Modifier.PRIVATE, Modifier.FINAL)
+ .addField(ObjectFactory.class, "keyFactory", Modifier.PRIVATE, Modifier.FINAL)
+ .addField(ObjectFactory.class, "valFactory", Modifier.PRIVATE, Modifier.FINAL)
+ .addMethod(
+ MethodSpec.constructorBuilder()
.addModifiers(Modifier.PUBLIC)
- .addAnnotation(AnnotationSpec.builder(Generated.class).addMember("value", getClass().getCanonicalName()).build())
- .addField(SchemaDescriptor.class, "schema", Modifier.PRIVATE, Modifier.FINAL)
- .addField(ObjectFactory.class, "keyFactory", Modifier.PRIVATE, Modifier.FINAL)
- .addField(ObjectFactory.class, "valFactory", Modifier.PRIVATE, Modifier.FINAL)
- .addField(ArrayTypeName.of(VarHandle.class), "fieldAccessors", Modifier.PRIVATE, Modifier.FINAL)
- .addMethod(
- MethodSpec.constructorBuilder()
- .addModifiers(Modifier.PUBLIC)
- .addParameter(SchemaDescriptor.class, "schema")
- .addParameter(Class.class, "keyClass")
- .addParameter(Class.class, "valClass")
- .addStatement("this.schema = schema")
- .addStatement("this.keyFactory = $T.factoryForClass(keyClass)", MarshallerUtil.class)
- .addStatement("this.valFactory = $T.factoryForClass(keyClass)", MarshallerUtil.class)
- .addStatement("this.fieldAccessors = null")
- .build()
- )
- .addMethod(generateHelpersMetod(schema))
- .addMethod(generateSerializeMethod(keyMarsh, valMarsh))
- .addMethod(generateDeserializeKeyMethod(keyMarsh))
- .addMethod(generateDeserializeValueMethod())
+ .addParameter(SchemaDescriptor.class, "schema")
+ .addParameter(Class.class, "keyClass")
+ .addParameter(Class.class, "valClass")
+ .addStatement("this.schema = schema")
+ .addStatement("this.keyFactory = $T.factoryForClass(keyClass)", MarshallerUtil.class)
+ .addStatement("this.valFactory = $T.factoryForClass(valClass)", MarshallerUtil.class)
.build()
)
+ .addMethod(generateHelpersMetod(schema, keyMarsh, valMarsh))
+ .addMethod(generateSerializeMethod(keyMarsh, valMarsh))
+ .addMethod(generateDeserializeKeyMethod(keyMarsh))
+ .addMethod(generateDeserializeValueMethod(valMarsh));
+
+ return JavaFile
+ .builder(SERIALIZER_PACKAGE_NAME, classBuilder.build())
+ .addStaticImport(TupleAccessorExpr.class, "*")
+ .addStaticImport(MethodHandles.class, "Lookup")
.skipJavaLangImports(true)
- .indent(TAB)
- .build()
- .writeTo(sb);
-
- return sb.toString();
+ .indent(" ")
+ .build();
}
catch (Exception ex) {
//TODO: fallback to java serializer?
@@ -189,7 +145,33 @@ public class JaninoSerializerGenerator implements SerializerFactory {
}
}
- private MethodSpec generateHelpersMetod(SchemaDescriptor schema) {
+ private void initFieldHandlers(MarshallerExprGenerator keyMarsh, MarshallerExprGenerator valMarsh,
+ TypeSpec.Builder classBuilder) {
+ if (keyMarsh.isSimpleType() && valMarsh.isSimpleType())
+ return;
+
+ final CodeBlock.Builder staticInitBuilder = CodeBlock.builder()
+ .addStatement("$T.Lookup lookup", MethodHandles.class)
+ .beginControlFlow("try");
+
+ if (!keyMarsh.isSimpleType()) {
+ staticInitBuilder.addStatement("lookup = $T.privateLookupIn($T.class, $T.lookup())", MethodHandles.class, keyMarsh.getClazz(), MethodHandles.class);
+ keyMarsh.staticHandlers(classBuilder, staticInitBuilder);
+ }
+
+ if (!valMarsh.isSimpleType()) {
+ staticInitBuilder.addStatement("lookup = $T.privateLookupIn($T.class, $T.lookup())", MethodHandles.class, valMarsh.getClazz(), MethodHandles.class);
+ valMarsh.staticHandlers(classBuilder, staticInitBuilder);
+ }
+
+ staticInitBuilder.nextControlFlow("catch ($T | $T ex)", ReflectiveOperationException.class, SecurityException.class)
+ .addStatement("throw new $T(ex)", IllegalStateException.class)
+ .endControlFlow();
+
+ classBuilder.addStaticBlock(staticInitBuilder.build());
+ }
+
+ private MethodSpec generateHelpersMetod(SchemaDescriptor schema, MarshallerExprGenerator keyMarsh, MarshallerExprGenerator valMarsh) {
final MethodSpec.Builder builder = MethodSpec
.methodBuilder("createAssembler")
.addModifiers(Modifier.PRIVATE)
@@ -210,9 +192,9 @@ public class JaninoSerializerGenerator implements SerializerFactory {
for (int i = keyCols.firstVarlengthColumn(); i < keyCols.length(); i++) {
assert !keyCols.column(i).type().spec().fixedLength();
- block.addStatement("assert !keyCols.column($L).type().spec().fixedLength()", i)
- .addStatement("fVal = fieldAccessors[$L].get(key)", i)
- .beginControlFlow("if (fVal != null)")
+ block.addStatement("fVal = $L", keyMarsh.getValueCode("key", i).toString());
+
+ block.beginControlFlow("if (fVal != null)")
.addStatement("nonNullVarlenKeysSize += $T.getValueSize(fVal, keyCols.column($L).type())", MarshallerUtil.class, i)
.addStatement("nonNullVarlenKeys++")
.endControlFlow();
@@ -225,7 +207,7 @@ public class JaninoSerializerGenerator implements SerializerFactory {
.addCode("}\n");
}
- Columns valCols = schema.keyColumns();
+ Columns valCols = schema.valueColumns();
if (valCols.firstVarlengthColumn() >= 0) {
final CodeBlock.Builder block = CodeBlock.builder().indent()
.addStatement("$T fVal", Object.class);// Temporary vars.
@@ -233,9 +215,9 @@ public class JaninoSerializerGenerator implements SerializerFactory {
for (int i = valCols.firstVarlengthColumn(); i < valCols.length(); i++) {
assert !valCols.column(i).type().spec().fixedLength();
- block.addStatement("assert !valCols.column($L).type().spec().fixedLength()", i)
- .addStatement("fVal = fieldAccessors[$L].get(val)", i + schema.keyColumns().length())
- .beginControlFlow("if (fVal != null)")
+ block.addStatement("fVal = $L", valMarsh.getValueCode("val", i).toString());
+
+ block.beginControlFlow("if (fVal != null)")
.addStatement("nonNullVarlenValuesSize += $T.getValueSize(fVal, valCols.column($L).type())", MarshallerUtil.class, i)
.addStatement("nonNullVarlenValues++")
.endControlFlow();
@@ -256,7 +238,7 @@ public class JaninoSerializerGenerator implements SerializerFactory {
return builder.build();
}
- @NotNull private MethodSpec generateDeserializeValueMethod() {
+ @NotNull private MethodSpec generateDeserializeValueMethod(MarshallerExprGenerator valMarsh) {
return MethodSpec
.methodBuilder("deserializeValue")
.addAnnotation(Override.class)
@@ -264,12 +246,18 @@ public class JaninoSerializerGenerator implements SerializerFactory {
.addParameter(ArrayTypeName.of(TypeName.BYTE), "data")
.addException(SerializationException.class)
.returns(TypeName.OBJECT)
- .addStatement("return null")
- .build();
+
+ .beginControlFlow("try")
+ .addStatement("$T tuple = new $T(schema, data)", Tuple.class, ByteBufferTuple.class)
+ .addCode(valMarsh.unmarshallObjectCode("tuple"))
+
+ .nextControlFlow("catch($T th)", Throwable.class)
+ .addStatement("throw new $T(th)", SerializationException.class)
+ .endControlFlow().build();
}
@NotNull private MethodSpec generateDeserializeKeyMethod(MarshallerExprGenerator keyMarsh) {
- final MethodSpec.Builder builder = MethodSpec
+ return MethodSpec
.methodBuilder("deserializeKey")
.addAnnotation(Override.class)
.addModifiers(Modifier.PUBLIC)
@@ -283,9 +271,7 @@ public class JaninoSerializerGenerator implements SerializerFactory {
.nextControlFlow("catch($T th)", Throwable.class)
.addStatement("throw new $T(th)", SerializationException.class)
- .endControlFlow();
-
- return builder.build();
+ .endControlFlow().build();
}
@NotNull
@@ -297,7 +283,7 @@ public class JaninoSerializerGenerator implements SerializerFactory {
.addParameter(TypeName.OBJECT, "key")
.addParameter(TypeName.OBJECT, "val")
.addException(SerializationException.class)
- .returns(ArrayTypeName.of(TypeName.BYTE.unbox()))
+ .returns(ArrayTypeName.of(TypeName.BYTE))
.beginControlFlow("try")
.addStatement("$T asm = createAssembler(key, val)", TupleAssembler.class)
@@ -312,74 +298,6 @@ public class JaninoSerializerGenerator implements SerializerFactory {
}
/**
- * Generates serializer code.
- *
- * @param ce Class body evaluator.
- * @param schema Schema descriptor.
- * @param keyClass Key class.
- * @param valClass Value class.
- * @return Generated class code.
- */
- private String generateSerializerClassCode(
- IClassBodyEvaluator ce,
- SchemaDescriptor schema,
- Class<?> keyClass,
- Class<?> valClass
- ) {
- final String className = SERIALIZER_CLASS_NAME_PREFIX + schema.version();
-
- // Prerequisites.
- ce.setClassName(SERIALIZER_PACKAGE_NAME + className);
- ce.setImplementedInterfaces(new Class[] {Serializer.class});
- ce.setDefaultImports(
- "java.util.UUID",
- "java.util.BitSet",
-
- "org.apache.ignite.internal.schema.ByteBufferTuple",
- "org.apache.ignite.internal.schema.Columns",
- "org.apache.ignite.internal.schema.SchemaDescriptor",
- "org.apache.ignite.internal.schema.Tuple",
- "org.apache.ignite.internal.schema.TupleAssembler",
- "org.apache.ignite.internal.util.IgniteUnsafeUtils",
- "org.apache.ignite.internal.util.ObjectFactory"
- );
-
- // Build field accessor generators.
- final MarshallerExprGenerator keyMarsh = createObjectMarshaller(keyClass, "keyFactory", schema.keyColumns(), 0);
- final MarshallerExprGenerator valMarsh = createObjectMarshaller(valClass, "valFactory", schema.valueColumns(), schema.keyColumns().length());
-
- // Create buffer.
- final StringBuilder sb = new StringBuilder(INITIAL_BUFFER_SIZE);
-
- // Append class fields desctiption.
- sb.append("private final SchemaDescriptor schema;" + LF);
-
- if (!keyMarsh.isSimpleTypeMarshaller())
- sb.append("private final ObjectFactory keyFactory;" + LF);
- if (!valMarsh.isSimpleTypeMarshaller())
- sb.append("private final ObjectFactory valFactory;" + LF);
-
- // Append constructor code.
- sb.append(LF + "public ").append(className).append("(SchemaDescriptor schema, Class kClass, Class vClass) {" + LF);
- sb.append(TAB + "this.schema = schema; " + LF);
- if (!keyMarsh.isSimpleTypeMarshaller())
- sb.append(TAB + "keyFactory = new ObjectFactory(kClass);" + LF);
- if (!valMarsh.isSimpleTypeMarshaller())
- sb.append(TAB + "valFactory = new ObjectFactory(vClass);" + LF);
- sb.append("}" + LF);
-
- // Generate and append helper-methods.
- generateTupleFactoryMethod(sb, schema, keyMarsh, valMarsh);
-
- // Generate and append Serializer interface methods.
- appendSerializeMethod(sb, keyMarsh, valMarsh);
- writeDeserializeKeyMethod(sb, keyMarsh);
- writeDeserializeValueMethod(sb, valMarsh);
-
- return sb.toString();
- }
-
- /**
* Creates marshal/unmarshall expressions generator for object.
*
* @param aClass Object class.
@@ -397,173 +315,8 @@ public class JaninoSerializerGenerator implements SerializerFactory {
BinaryMode mode = MarshallerUtil.mode(aClass);
if (mode != null)
- return new IdentityObjectMarshallerExprGenerator(
- FieldAccessExprGenerator.createIdentityAccessor(mode, firstColIdx),
- TupleAccessorExpr.createAccessor(mode, firstColIdx)
- );
-
- FieldAccessExprGenerator[] accessors = new FieldAccessExprGenerator[columns.length()];
- TupleAccessorExpr[] tupleAccessorExprs = new TupleAccessorExpr[] {};
- try {
- for (int i = 0; i < columns.length(); i++) {
- final Field field = aClass.getDeclaredField(columns.column(i).name());
-
- accessors[i] = FieldAccessExprGenerator.createAccessor(
- MarshallerUtil.mode(field.getType()),
- firstColIdx + i /* schma absolute index. */,
- 0L);// IgniteUnsafeUtils.objectFieldOffset(field));
- }
- }
- catch (NoSuchFieldException ex) {
- throw new IllegalStateException(ex);
- }
-
- return new MarshallerExprGenerator(factoryRefExpr, accessors, tupleAccessorExprs);
- }
-
- /**
- * Appends {@link Serializer#serialize(Object, Object)} method code.
- *
- * @param sb String buffer to append to.
- * @param keyMarsh Marshall expression generator for key.
- * @param valMarsh Marshall expression generator for value.
- */
- private void appendSerializeMethod(
- StringBuilder sb,
- MarshallerExprGenerator keyMarsh,
- MarshallerExprGenerator valMarsh
- ) {
- // Mehtod signature.
- sb.append(LF + "@Override public byte[] serialize(Object key, Object val) throws SerializationException {" + LF);
- sb.append(TAB + "TupleAssembler asm = createAssembler(key, val);" + LF);
-
- // Key marshal script.
- sb.append(TAB + "{" + LF);
- sb.append(TAB + TAB + "Object obj = key;" + LF);
- keyMarsh.appendMarshallObjectExpr(sb, TAB + TAB);
- sb.append(TAB + "}" + LF);
-
- // Value marshal script.
- sb.append(TAB + " {" + LF);
- sb.append(TAB + TAB + "Object obj = val;" + LF);
- valMarsh.appendMarshallObjectExpr(sb, TAB + TAB);
- sb.append(TAB + "}" + LF);
-
- // Return statement.
- sb.append(TAB + "return asm.build();" + LF);
- sb.append("}" + LF);
- }
-
- /**
- * Appends {@link Serializer#deserializeKey(byte[])} method code.
- *
- * @param sb String buffer to append to.
- * @param keyMarsh Unmarshall expression generator for key.
- */
- private void writeDeserializeKeyMethod(StringBuilder sb, MarshallerExprGenerator keyMarsh) {
- // Mehtod signature.
- sb.append(LF + "@Override public Object deserializeKey(byte[] data) throws SerializationException {" + LF);
- sb.append(TAB + "Tuple tuple = new ByteBufferTuple(schema, data);" + LF);
-
- // Key unmarshal script.
- keyMarsh.appendUnmarshallObjectExpr(sb, TAB);
-
- // Return statement.
- sb.append(TAB + "return obj;" + LF);
- sb.append("}" + LF);
- }
-
- /**
- * Appends {@link Serializer#deserializeValue(byte[])} method code.
- *
- * @param sb String buffer to append to.
- * @param valMarsh Unmarshall expression generator for value.
- */
- private void writeDeserializeValueMethod(StringBuilder sb, MarshallerExprGenerator valMarsh) {
- // Mehtod signature.
- sb.append(LF + "@Override public Object deserializeValue(byte[] data) throws SerializationException {" + LF);
- sb.append(TAB + "Tuple tuple = new ByteBufferTuple(schema, data);" + LF);
-
- // Key unmarshal script.
- valMarsh.appendUnmarshallObjectExpr(sb, TAB);
-
- // Return statement.
- sb.append(TAB + "return obj;" + LF);
- sb.append("}" + LF);
- }
-
- /**
- * Appends helper methods code.
- *
- * @param sb String buffer to append to.
- * @param schema Schema descriptor.
- * @param keyMarsh Marshall expression generator for key.
- * @param valMarsh Marshall expression generator for value.
- */
- private void generateTupleFactoryMethod(
- StringBuilder sb,
- SchemaDescriptor schema,
- MarshallerExprGenerator keyMarsh,
- MarshallerExprGenerator valMarsh
- ) {
- // Method signature.
- sb.append(LF + "TupleAssembler createAssembler(Object key, Object val) {" + LF);
- // Local variables.
- sb.append(TAB + "int nonNullVarlenKeys = 0; int nonNullVarlenValues = 0;" + LF);
- sb.append(TAB + "int nonNullVarlenKeysSize = 0; int nonNullVarlenValuesSize = 0;" + LF);
- sb.append(LF);
- sb.append(TAB + "Columns keyCols = schema.keyColumns();" + LF);
- sb.append(TAB + "Columns valCols = schema.valueColumns();" + LF);
- sb.append(LF);
-
- Columns keyCols = schema.keyColumns();
- if (keyCols.firstVarlengthColumn() >= 0) {
- // Appends key analyzer code-block.
- sb.append(TAB + "{" + LF);
- sb.append(TAB + TAB + "Object fVal, obj = key;" + LF); // Temporary vars.
-
- for (int i = keyCols.firstVarlengthColumn(); i < keyCols.length(); i++) {
- assert !keyCols.column(i).type().spec().fixedLength();
-
- sb.append(TAB + TAB + "assert !keyCols.column(").append(i).append(").type().spec().fixedLength();" + LF);
- sb.append(TAB + TAB + "fVal = ").append(keyMarsh.accessors[i].getFieldExpr()).append(";" + LF);
- sb.append(TAB + TAB + "if (fVal != null) {" + LF);
- sb.append(TAB + TAB + TAB + "nonNullVarlenKeysSize += MarshallerUtil.getValueSize(fVal, keyCols.column(").append(i).append(").type());").append(LF);
- sb.append(TAB + TAB + TAB + "nonNullVarlenKeys++;" + LF);
- sb.append(TAB + TAB + "}" + LF);
- }
-
- sb.append(TAB + "}" + LF);
- }
-
- Columns valCols = schema.valueColumns();
- if (valCols.firstVarlengthColumn() >= 0) {
- // Appends value analyzer code-block.
- sb.append(TAB + "{" + LF);
- sb.append(TAB + TAB + "Object fVal, obj = val;" + LF); // Temporary vars.
-
- for (int i = valCols.firstVarlengthColumn(); i < valCols.length(); i++) {
- assert !valCols.column(i).type().spec().fixedLength();
-
- sb.append(TAB + TAB + "assert !valCols.column(").append(i).append(").type().spec().fixedLength();" + LF);
- sb.append(TAB + TAB + "fVal = ").append(valMarsh.accessors[i].getFieldExpr()).append(";" + LF);
- sb.append(TAB + TAB + "if (fVal != null) {" + LF);
- sb.append(TAB + TAB + TAB + "nonNullVarlenValuesSize += MarshallerUtil.getValueSize(fVal, valCols.column(").append(i).append(").type());" + LF);
- sb.append(TAB + TAB + TAB + "nonNullVarlenValues++;" + LF);
- sb.append(TAB + TAB + "}" + LF);
- }
- sb.append(TAB + "}" + LF);
- }
-
- // Calculate tuple size.
- sb.append(LF);
- sb.append(TAB + "int size = TupleAssembler.tupleSize(" + LF);
- sb.append(TAB + TAB + "keyCols, nonNullVarlenKeys, nonNullVarlenKeysSize, " + LF);
- sb.append(TAB + TAB + "valCols, nonNullVarlenValues, nonNullVarlenValuesSize); " + LF);
- sb.append(LF);
-
- // Return statement.
- sb.append(TAB + "return new TupleAssembler(schema, size, nonNullVarlenKeys, nonNullVarlenValues);" + LF);
- sb.append("}" + LF);
+ return new IdentityObjectMarshallerExprGenerator(aClass, TupleAccessorExpr.createAccessor(mode, firstColIdx));
+ else
+ return new MarshallerExprGenerator(aClass, factoryRefExpr, columns, firstColIdx);
}
}
diff --git a/modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/generator/MarshallerExprGenerator.java b/modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/generator/MarshallerExprGenerator.java
index 8087e2c..53be5ed 100644
--- a/modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/generator/MarshallerExprGenerator.java
+++ b/modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/generator/MarshallerExprGenerator.java
@@ -18,7 +18,13 @@
package org.apache.ignite.internal.schema.marshaller.generator;
import com.squareup.javapoet.CodeBlock;
+import com.squareup.javapoet.FieldSpec;
+import com.squareup.javapoet.TypeSpec;
import java.lang.invoke.VarHandle;
+import java.lang.reflect.Field;
+import javax.lang.model.element.Modifier;
+import org.apache.ignite.internal.schema.Columns;
+import org.apache.ignite.internal.schema.marshaller.MarshallerUtil;
import org.apache.ignite.internal.schema.marshaller.Serializer;
/**
@@ -28,93 +34,91 @@ class MarshallerExprGenerator {
/** Object factory regerence expression. */
private final String factoryRefExpr;
+ private final Class<?> tClass;
+
+ private final Columns columns;
+
/** Object field access expression generators. */
- protected FieldAccessExprGenerator[] accessors;
protected TupleAccessorExpr[] tupleAccessors;
/**
* Constructor.
*
+ * @param tClass
* @param factoryRefExpr Object factory regerence expression.
- * @param accessors Object field access expression generators.
*/
- public MarshallerExprGenerator(String factoryRefExpr, FieldAccessExprGenerator[] accessors,
- TupleAccessorExpr[] tupleAccessors) {
- this.accessors = accessors;
+ public MarshallerExprGenerator(Class<?> tClass, String factoryRefExpr, Columns columns, int firstColIdx) {
this.factoryRefExpr = factoryRefExpr;
- this.tupleAccessors = tupleAccessors;
+ this.tClass = tClass;
+
+ this.columns = columns;
+ tupleAccessors = new TupleAccessorExpr[this.columns.length()];
+ try {
+ for (int i = 0; i < columns.length(); i++) {
+ final Field field = tClass.getDeclaredField(columns.column(i).name());
+
+ tupleAccessors[i] = TupleAccessorExpr.createAccessor(MarshallerUtil.mode(field.getType()), i + firstColIdx);
+ }
+ }
+ catch (NoSuchFieldException ex) {
+ throw new IllegalStateException(ex);
+ }
}
- /**
- * @return {@code true} if it is simple object marshaller, {@code false} otherwise.
- */
- boolean isSimpleTypeMarshaller() {
- return factoryRefExpr == null;
+ public MarshallerExprGenerator(Class<?> tClass, Object expr, TupleAccessorExpr[] tupleAccessorExprs) {
+ this.factoryRefExpr = null;
+ this.tClass = tClass;
+ columns = null;
+ this.tupleAccessors = tupleAccessorExprs;
}
/**
- * Appends unmashall object code to string builder.
- *
- * @param sb String builder.
- * @param indent Line indentation.
+ * @return {@code true} if it is simple object marshaller, {@code false} otherwise.
*/
- public void appendUnmarshallObjectExpr(StringBuilder sb, String indent) {
- assert factoryRefExpr != null;
-
- sb.append(indent).append("Object obj;" + JaninoSerializerGenerator.LF);
- // Try.
- sb.append(indent).append("try {" + JaninoSerializerGenerator.LF);
- sb.append(indent).append(JaninoSerializerGenerator.TAB + "obj = ").append(factoryRefExpr).append(".create();" + JaninoSerializerGenerator.LF);
-
- // Read column from tuple to object field.
- for (int i = 0; i < accessors.length; i++)
- accessors[i].appendPutFieldExpr(sb, accessors[i].readColumnExpr(), indent + JaninoSerializerGenerator.TAB);
-
- // Catch and rethrow wrapped exeption.
- sb.append(indent).append("} catch (Exception ex) {" + JaninoSerializerGenerator.LF);
- sb.append(indent).append(JaninoSerializerGenerator.TAB + "throw new SerializationException(\"Failed to instantiate object: \" + ")
- .append(factoryRefExpr).append(".getClazz().getName(), ex);").append(JaninoSerializerGenerator.LF);
- sb.append(indent).append("}" + JaninoSerializerGenerator.LF);
+ boolean isSimpleType() {
+ return false;
}
- /**
- * Appends mashall object code to string builder.
- *
- * @param sb String builder.
- * @param indent Line indentation.
- */
- public void appendMarshallObjectExpr(StringBuilder sb, String indent) {
- // Try.
- sb.append(indent).append("try {" + JaninoSerializerGenerator.LF);
-
- // Write object field to tuple assembler.
- for (int i = 0; i < accessors.length; i++)
- accessors[i].appendWriteColumnExpr(sb, accessors[i].getFieldExpr(), indent + JaninoSerializerGenerator.TAB);
-
- // Catch and rethrow wrapped exeption.
- sb.append(indent).append("} catch (Exception ex) {" + JaninoSerializerGenerator.LF);
- sb.append(indent).append(JaninoSerializerGenerator.TAB + "throw new SerializationException(ex);").append(JaninoSerializerGenerator.LF);
- sb.append(indent).append("}" + JaninoSerializerGenerator.LF);
+ Class<?> getClazz() {
+ return tClass;
}
public CodeBlock unmarshallObjectCode(String tupleExpr) {
final CodeBlock.Builder builder = CodeBlock.builder()
.add("Object obj = ").add(factoryRefExpr).addStatement(".create()");
- for (int i = 0; i < tupleAccessors.length; i++) {
- builder.addStatement("fieldAccessor[$L].set(obj, $L)", i, tupleAccessors[i].read(tupleExpr).toString());
- }
+ for (int i = 0; i < tupleAccessors.length; i++)
+ builder.addStatement("FIELD_HANDLE_$L.set(obj, $L)", tupleAccessors[i].colIdx, tupleAccessors[i].read(tupleExpr).toString());
- builder.addStatement("return obj");
+ builder.addStatement("return obj");
return builder.build();
}
+ public CodeBlock getValueCode(String objVar, int i) {
+ return CodeBlock.of("FIELD_HANDLE_$L.get($L)", tupleAccessors[i].colIdx, objVar);
+ }
+
public CodeBlock marshallObjectCode(String asm, String objVar) {
final CodeBlock.Builder builder = CodeBlock.builder();
for (int i = 0; i < tupleAccessors.length; i++)
- builder.addStatement(tupleAccessors[i].write(asm, CodeBlock.of("fieldAccessor[$L].get($L)", i, objVar).toString()));
+ builder.addStatement(tupleAccessors[i].write(asm, getValueCode(objVar, i).toString()).toString());
return builder.build();
}
+
+ public void staticHandlers(TypeSpec.Builder builder, CodeBlock.Builder staticBuilder) {
+ for (int i = 0; i < tupleAccessors.length; i++) {
+ builder.addField(FieldSpec.builder(
+ VarHandle.class,
+ CodeBlock.of("FIELD_HANDLE_$L", tupleAccessors[i].colIdx).toString(),
+ Modifier.PRIVATE,
+ Modifier.FINAL,
+ Modifier.STATIC)
+ .build());
+
+ staticBuilder.addStatement("FIELD_HANDLE_$L = lookup.unreflectVarHandle($T.class.getDeclaredField($S))",
+ tupleAccessors[i].colIdx, tClass, columns.column(i).name());
+ }
+ }
}
diff --git a/modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/generator/TupleAccessorExpr.java b/modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/generator/TupleAccessorExpr.java
index e1b782d..ccca864 100644
--- a/modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/generator/TupleAccessorExpr.java
+++ b/modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/generator/TupleAccessorExpr.java
@@ -21,6 +21,8 @@ import com.squareup.javapoet.CodeBlock;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
+import java.util.BitSet;
+import java.util.UUID;
import org.apache.ignite.internal.schema.Tuple;
import org.apache.ignite.internal.schema.TupleAssembler;
import org.apache.ignite.internal.schema.marshaller.BinaryMode;
@@ -29,52 +31,68 @@ import org.apache.ignite.internal.schema.marshaller.BinaryMode;
* Object field access expression generators.
*/
public class TupleAccessorExpr {
- public static final MethodHandle BYTE_READ;
- public static final MethodHandle SHORT_READ;
- public static final MethodHandle INT_READ;
- public static final MethodHandle LONG_READ;
- public static final MethodHandle FLOAT_READ;
- public static final MethodHandle DOUBLE_READ;
- public static final MethodHandle BYTE_BOXED_READ;
- public static final MethodHandle SHORT_BOXED_READ;
- public static final MethodHandle INT_BOXED_READ;
- public static final MethodHandle LONG_BOXED_READ;
- public static final MethodHandle FLOAT_BOXED_READ;
- public static final MethodHandle DOUBLE_BOXED_READ;
+ public static final MethodHandle READ_BYTE;
+ public static final MethodHandle READ_SHORT;
+ public static final MethodHandle READ_INT;
+ public static final MethodHandle READ_LONG;
+ public static final MethodHandle READ_FLOAT;
+ public static final MethodHandle READ_DOUBLE;
+ public static final MethodHandle READ_BYTE_BOXED;
+ public static final MethodHandle READ_SHORT_BOXED;
+ public static final MethodHandle READ_INT_BOXED;
+ public static final MethodHandle READ_LONG_BOXED;
+ public static final MethodHandle READ_FLOAT_BOXED;
+ public static final MethodHandle READ_DOUBLE_BOXED;
+ public static final MethodHandle READ_UUID;
+ public static final MethodHandle READ_BITSET;
+ public static final MethodHandle READ_STRING;
+ public static final MethodHandle READ_BYTE_ARR;
- public static final MethodHandle BYTE_WRITE;
- public static final MethodHandle SHORT_WRITE;
- public static final MethodHandle INT_WRITE;
- public static final MethodHandle LONG_WRITE;
- public static final MethodHandle FLOAT_WRITE;
- public static final MethodHandle DOUBLE_WRITE;
- public static final MethodHandle NULL_WRITE;
+ public static final MethodHandle WRITE_NULL;
+ public static final MethodHandle WRITE_BYTE;
+ public static final MethodHandle WRITE_SHORT;
+ public static final MethodHandle WRITE_INT;
+ public static final MethodHandle WRITE_LONG;
+ public static final MethodHandle WRITE_FLOAT;
+ public static final MethodHandle WRITE_DOUBLE;
+ public static final MethodHandle WRITE_UUID;
+ public static final MethodHandle WRITE_BITSET;
+ public static final MethodHandle WRITE_STRING;
+ public static final MethodHandle WRITE_BYTE_ARR;
static {
try {
- MethodHandles.Lookup lookup = MethodHandles.privateLookupIn(Tuple.class,MethodHandles.lookup());
+ MethodHandles.Lookup lookup = MethodHandles.privateLookupIn(Tuple.class, MethodHandles.lookup());
- BYTE_READ = lookup.findVirtual(Tuple.class, "byteValue", MethodType.methodType(byte.class, int.class));
- SHORT_READ = lookup.findVirtual(Tuple.class, "shortValue", MethodType.methodType(short.class, int.class));
- INT_READ = lookup.findVirtual(Tuple.class, "intValue", MethodType.methodType(int.class, int.class));
- LONG_READ = lookup.findVirtual(Tuple.class, "longValue", MethodType.methodType(long.class, int.class));
- FLOAT_READ = lookup.findVirtual(Tuple.class, "floatValue", MethodType.methodType(float.class, int.class));
- DOUBLE_READ = lookup.findVirtual(Tuple.class, "doubleValue", MethodType.methodType(double.class, int.class));
- BYTE_BOXED_READ = lookup.findVirtual(Tuple.class, "byteValueBoxed", MethodType.methodType(Byte.class, int.class));
- SHORT_BOXED_READ = lookup.findVirtual(Tuple.class, "shortValueBoxed", MethodType.methodType(Short.class, int.class));
- INT_BOXED_READ = lookup.findVirtual(Tuple.class, "intValueBoxed", MethodType.methodType(Integer.class, int.class));
- LONG_BOXED_READ = lookup.findVirtual(Tuple.class, "longValueBoxed", MethodType.methodType(Long.class, int.class));
- FLOAT_BOXED_READ = lookup.findVirtual(Tuple.class, "floatValueBoxed", MethodType.methodType(Float.class, int.class));
- DOUBLE_BOXED_READ = lookup.findVirtual(Tuple.class, "doubleValueBoxed", MethodType.methodType(Double.class, int.class));
+ READ_BYTE = lookup.findVirtual(Tuple.class, "byteValue", MethodType.methodType(byte.class, int.class));
+ READ_SHORT = lookup.findVirtual(Tuple.class, "shortValue", MethodType.methodType(short.class, int.class));
+ READ_INT = lookup.findVirtual(Tuple.class, "intValue", MethodType.methodType(int.class, int.class));
+ READ_LONG = lookup.findVirtual(Tuple.class, "longValue", MethodType.methodType(long.class, int.class));
+ READ_FLOAT = lookup.findVirtual(Tuple.class, "floatValue", MethodType.methodType(float.class, int.class));
+ READ_DOUBLE = lookup.findVirtual(Tuple.class, "doubleValue", MethodType.methodType(double.class, int.class));
+ READ_BYTE_BOXED = lookup.findVirtual(Tuple.class, "byteValueBoxed", MethodType.methodType(Byte.class, int.class));
+ READ_SHORT_BOXED = lookup.findVirtual(Tuple.class, "shortValueBoxed", MethodType.methodType(Short.class, int.class));
+ READ_INT_BOXED = lookup.findVirtual(Tuple.class, "intValueBoxed", MethodType.methodType(Integer.class, int.class));
+ READ_LONG_BOXED = lookup.findVirtual(Tuple.class, "longValueBoxed", MethodType.methodType(Long.class, int.class));
+ READ_FLOAT_BOXED = lookup.findVirtual(Tuple.class, "floatValueBoxed", MethodType.methodType(Float.class, int.class));
+ READ_DOUBLE_BOXED = lookup.findVirtual(Tuple.class, "doubleValueBoxed", MethodType.methodType(Double.class, int.class));
+ READ_UUID = lookup.findVirtual(Tuple.class, "uuidValue", MethodType.methodType(UUID.class, int.class));
+ READ_BITSET = lookup.findVirtual(Tuple.class, "bitmaskValue", MethodType.methodType(BitSet.class, int.class));
+ READ_STRING = lookup.findVirtual(Tuple.class, "stringValue", MethodType.methodType(String.class, int.class));
+ READ_BYTE_ARR = lookup.findVirtual(Tuple.class, "bytesValue", MethodType.methodType(byte[].class, int.class));
- lookup = MethodHandles.privateLookupIn(TupleAssembler.class,MethodHandles.lookup());
- NULL_WRITE = lookup.findVirtual(TupleAssembler.class, "appendNull", MethodType.methodType(void.class));
- BYTE_WRITE = lookup.findVirtual(TupleAssembler.class, "appendByte", MethodType.methodType(void.class, byte.class));
- SHORT_WRITE = lookup.findVirtual(TupleAssembler.class, "appendShort", MethodType.methodType(void.class, short.class));
- INT_WRITE = lookup.findVirtual(TupleAssembler.class, "appendInt", MethodType.methodType(void.class, int.class));
- LONG_WRITE = lookup.findVirtual(TupleAssembler.class, "appendLong", MethodType.methodType(void.class, long.class));
- FLOAT_WRITE = lookup.findVirtual(TupleAssembler.class, "appendFloat", MethodType.methodType(void.class, float.class));
- DOUBLE_WRITE = lookup.findVirtual(TupleAssembler.class, "appendDouble", MethodType.methodType(void.class, double.class));
+ lookup = MethodHandles.privateLookupIn(TupleAssembler.class, MethodHandles.lookup());
+ WRITE_NULL = lookup.findVirtual(TupleAssembler.class, "appendNull", MethodType.methodType(void.class));
+ WRITE_BYTE = lookup.findVirtual(TupleAssembler.class, "appendByte", MethodType.methodType(void.class, byte.class));
+ WRITE_SHORT = lookup.findVirtual(TupleAssembler.class, "appendShort", MethodType.methodType(void.class, short.class));
+ WRITE_INT = lookup.findVirtual(TupleAssembler.class, "appendInt", MethodType.methodType(void.class, int.class));
+ WRITE_LONG = lookup.findVirtual(TupleAssembler.class, "appendLong", MethodType.methodType(void.class, long.class));
+ WRITE_FLOAT = lookup.findVirtual(TupleAssembler.class, "appendFloat", MethodType.methodType(void.class, float.class));
+ WRITE_DOUBLE = lookup.findVirtual(TupleAssembler.class, "appendDouble", MethodType.methodType(void.class, double.class));
+ WRITE_UUID = lookup.findVirtual(TupleAssembler.class, "appendUuid", MethodType.methodType(void.class, UUID.class));
+ WRITE_BITSET = lookup.findVirtual(TupleAssembler.class, "appendBitmask", MethodType.methodType(void.class, BitSet.class));
+ WRITE_STRING = lookup.findVirtual(TupleAssembler.class, "appendString", MethodType.methodType(void.class, String.class));
+ WRITE_BYTE_ARR = lookup.findVirtual(TupleAssembler.class, "appendBytes", MethodType.methodType(void.class, byte[].class));
}
catch (NoSuchMethodException | IllegalAccessException e) {
throw new IllegalStateException(e);
@@ -87,37 +105,37 @@ public class TupleAccessorExpr {
static TupleAccessorExpr createAccessor(BinaryMode mode, int colIdx) {
switch (mode) {
case P_BYTE:
- return new TupleAccessorExpr("BYTE_READ", "BYTE_WRITE", byte.class, colIdx);
+ return new TupleAccessorExpr("READ_BYTE", "WRITE_BYTE", byte.class, colIdx);
case P_SHORT:
- break;
+ return new TupleAccessorExpr("READ_SHORT", "WRITE_SHORT", short.class, colIdx);
case P_INT:
- break;
+ return new TupleAccessorExpr("READ_INT", "WRITE_INT", int.class, colIdx);
case P_LONG:
- break;
+ return new TupleAccessorExpr("READ_LONG", "WRITE_LONG", long.class, colIdx);
case P_FLOAT:
- break;
+ return new TupleAccessorExpr("READ_FLOAT", "WRITE_FLOAT", float.class, colIdx);
case P_DOUBLE:
- break;
+ return new TupleAccessorExpr("READ_DOUBLE", "WRITE_DOUBLE", double.class, colIdx);
case BYTE:
- return new TupleAccessorExpr("BYTE_BOXED_READ", "BYTE_WRITE", Byte.class, colIdx);
+ return new TupleAccessorExpr("READ_BYTE_BOXED", "WRITE_BYTE", Byte.class, colIdx);
case SHORT:
- break;
+ return new TupleAccessorExpr("READ_SHORT_BOXED", "WRITE_SHORT", Short.class, colIdx);
case INT:
- break;
+ return new TupleAccessorExpr("READ_INT_BOXED", "WRITE_INT", Integer.class, colIdx);
case LONG:
- break;
+ return new TupleAccessorExpr("READ_LONG_BOXED", "WRITE_LONG", Long.class, colIdx);
case FLOAT:
- break;
+ return new TupleAccessorExpr("READ_FLOAT_BOXED", "WRITE_FLOAT", Float.class, colIdx);
case DOUBLE:
- break;
+ return new TupleAccessorExpr("READ_DOUBLE_BOXED", "WRITE_DOUBLE", Double.class, colIdx);
case STRING:
- break;
+ return new TupleAccessorExpr("READ_STRING", "WRITE_STRING", String.class, colIdx);
case UUID:
- break;
+ return new TupleAccessorExpr("READ_UUID", "WRITE_UUID", UUID.class, colIdx);
case BYTE_ARR:
- break;
+ return new TupleAccessorExpr("READ_BYTE_ARR", "WRITE_BYTE_ARR", byte[].class, colIdx);
case BITSET:
- break;
+ return new TupleAccessorExpr("READ_BITSET", "WRITE_BITSET", BitSet.class, colIdx);
}
throw new IllegalStateException("Unsupported binary mode: " + mode);
@@ -125,7 +143,7 @@ public class TupleAccessorExpr {
private final String readExpr;
private final String writeExpr;
- private final int colIdx;
+ final int colIdx;
private TupleAccessorExpr(String readExpr, String writeExpr, Class<?> rType, int colIdx) {
this.readExpr = readExpr;
@@ -146,7 +164,7 @@ public class TupleAccessorExpr {
.add("{\n").indent()
.addStatement("$T fVal", rType)
.beginControlFlow("if((fVal = ($T)$L) == null)", rType, valExpr)
- .addStatement("$T.NULL_WRITE.invokeExact($L)", TupleAccessorExpr.class, asmVar)
+ .addStatement("$T.WRITE_NULL.invoke($L)", TupleAccessorExpr.class, asmVar)
.nextControlFlow("else")
.addStatement("$T.$L.invoke($L, fVal)", TupleAccessorExpr.class, writeExpr, asmVar)
.endControlFlow()
diff --git a/modules/commons/src/test/java/org/apache/ignite/internal/benchmarks/SerializerBenchmarkTest.java b/modules/commons/src/test/java/org/apache/ignite/internal/benchmarks/SerializerBenchmarkTest.java
index 1f0ebef..e84e73b 100644
--- a/modules/commons/src/test/java/org/apache/ignite/internal/benchmarks/SerializerBenchmarkTest.java
+++ b/modules/commons/src/test/java/org/apache/ignite/internal/benchmarks/SerializerBenchmarkTest.java
@@ -17,18 +17,21 @@
package org.apache.ignite.internal.benchmarks;
+import com.squareup.javapoet.JavaFile;
+import com.squareup.javapoet.MethodSpec;
+import com.squareup.javapoet.TypeSpec;
import java.lang.reflect.Field;
import java.util.Random;
import java.util.concurrent.TimeUnit;
+import javax.lang.model.element.Modifier;
import org.apache.ignite.internal.schema.Column;
import org.apache.ignite.internal.schema.Columns;
import org.apache.ignite.internal.schema.SchemaDescriptor;
+import org.apache.ignite.internal.schema.marshaller.MarshallerUtil;
import org.apache.ignite.internal.schema.marshaller.Serializer;
import org.apache.ignite.internal.schema.marshaller.SerializerFactory;
import org.apache.ignite.internal.util.Factory;
import org.apache.ignite.internal.util.ObjectFactory;
-import org.codehaus.commons.compiler.CompilerFactoryFactory;
-import org.codehaus.commons.compiler.IClassBodyEvaluator;
import org.openjdk.jmh.annotations.Benchmark;
import org.openjdk.jmh.annotations.BenchmarkMode;
import org.openjdk.jmh.annotations.Fork;
@@ -155,28 +158,32 @@ public class SerializerBenchmarkTest {
* @return Generated test object class.
* @throws Exception If failed.
*/
- private Class<?> createGeneratedObjectClass(int maxFields, Class<?> fieldType) throws Exception {
- final IClassBodyEvaluator ce = CompilerFactoryFactory.getDefaultCompilerFactory().newClassBodyEvaluator();
+ private Class<?> createGeneratedObjectClass(int maxFields, Class<?> fieldType) {
+ final String packageName = "org.apache.ignite.internal.benchmarks";
+ final String className = "TestObject";
- ce.setClassName("TestObject");
- ce.setDefaultImports("java.util.Random");
+ final TypeSpec.Builder classBuilder = TypeSpec.classBuilder(className).addModifiers(Modifier.PUBLIC);
- final StringBuilder sb = new StringBuilder();
for (int i = 0; i < maxFields; i++)
- sb.append(fieldType.getName()).append(" col").append(i).append(";\n");
+ classBuilder.addField(fieldType, "col" + i, Modifier.PRIVATE);
- // Constructor.
- sb.append("public TestObject() {\n");
- sb.append(" Random rnd = new Random();\n");
- for (int i = 0; i < maxFields; i++)
- sb.append(" col").append(i).append(" = rnd.nextLong();\n");
- sb.append("}\n");
+ { // Build constructor.
+ final MethodSpec.Builder builder = MethodSpec.constructorBuilder()
+ .addModifiers(Modifier.PUBLIC)
+ .addStatement("$T rnd = new $T()", Random.class, Random.class);
- try {
- ce.setParentClassLoader(getClass().getClassLoader());
- ce.cook(sb.toString());
+ for (int i = 0; i < maxFields; i++)
+ builder.addStatement("col$L = rnd.nextLong()", i);
+
+ classBuilder.addMethod(builder.build());
+ }
- return ce.getClazz();
+ final JavaFile javaFile = JavaFile.builder(packageName, classBuilder.build()).build();
+
+ final ClassLoader loader = MarshallerUtil.compileCode(javaFile);
+
+ try {
+ return loader.loadClass(packageName + '.' + className);
}
catch (Exception ex) {
throw new IllegalStateException("Failed to compile/instantiate generated Serializer.", ex);
diff --git a/modules/commons/src/test/java/org/apache/ignite/internal/schema/marshaller/JavaSerializerTest.java b/modules/commons/src/test/java/org/apache/ignite/internal/schema/marshaller/JavaSerializerTest.java
index d172e86..a9589e9 100644
--- a/modules/commons/src/test/java/org/apache/ignite/internal/schema/marshaller/JavaSerializerTest.java
+++ b/modules/commons/src/test/java/org/apache/ignite/internal/schema/marshaller/JavaSerializerTest.java
@@ -17,13 +17,19 @@
package org.apache.ignite.internal.schema.marshaller;
+import com.squareup.javapoet.JavaFile;
+import com.squareup.javapoet.MethodSpec;
+import com.squareup.javapoet.TypeSpec;
import java.util.Arrays;
import java.util.BitSet;
+import java.util.HashMap;
import java.util.List;
+import java.util.Map;
import java.util.Objects;
import java.util.Random;
import java.util.UUID;
import java.util.stream.Stream;
+import javax.lang.model.element.Modifier;
import org.apache.ignite.internal.schema.Bitmask;
import org.apache.ignite.internal.schema.Column;
import org.apache.ignite.internal.schema.Columns;
@@ -33,6 +39,7 @@ import org.apache.ignite.internal.schema.SchemaDescriptor;
import org.apache.ignite.internal.schema.TestUtils;
import org.apache.ignite.internal.schema.marshaller.generator.JaninoSerializerGenerator;
import org.apache.ignite.internal.schema.marshaller.reflection.JavaSerializerFactory;
+import org.apache.ignite.internal.util.ObjectFactory;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DynamicNode;
import org.junit.jupiter.api.TestFactory;
@@ -261,6 +268,45 @@ public class JavaSerializerTest {
);
}
+
+ /**
+ *
+ */
+ @ParameterizedTest
+ @MethodSource("serializerFactoryProvider")
+ public void testClassLoader(SerializerFactory factory) throws SerializationException {
+ Column[] keyCols = new Column[] {
+ new Column("key", LONG, false)
+ };
+
+ Column[] valCols = new Column[] {
+ new Column("col0", LONG, false),
+ new Column("col1", LONG, false),
+ new Column("col2", LONG, false),
+ };
+
+ SchemaDescriptor schema = new SchemaDescriptor(1, new Columns(keyCols), new Columns(valCols));
+
+ final Map<String, byte[]> classes = new HashMap<>();
+ final Class<?> valClass = createGeneratedObjectClass(Long.class, classes);
+ final ObjectFactory<?> objFactory = new ObjectFactory<>(valClass);
+
+ final Long key = rnd.nextLong();
+
+ if (factory instanceof JaninoSerializerGenerator)
+ ((JaninoSerializerGenerator)factory).setClasses(classes);
+
+ Serializer serializer = factory.create(schema, key.getClass(), valClass);
+
+ byte[] bytes = serializer.serialize(key, objFactory.create());
+
+ Object key1 = serializer.deserializeKey(bytes);
+ Object val1 = serializer.deserializeValue(bytes);
+
+ assertTrue(key.getClass().isInstance(key1));
+ assertTrue(valClass.isInstance(val1));
+ }
+
/**
* Generate random key-value pair of given types and
* check serialization and deserialization works fine.
@@ -318,6 +364,45 @@ public class JavaSerializerTest {
}
/**
+ * Generate class for test objects.
+ *
+ * @param fieldType Field type.
+ * @param classes
+ * @return Generated test object class.
+ */
+ private Class<?> createGeneratedObjectClass(Class<?> fieldType, Map<String, byte[]> classes) {
+ final String packageName = getClass().getPackageName();
+ final String className = "GeneratedTestObject";
+
+ final TypeSpec.Builder classBuilder = TypeSpec.classBuilder(className).addModifiers(Modifier.PUBLIC);
+
+ for (int i = 0; i < 3; i++)
+ classBuilder.addField(fieldType, "col" + i, Modifier.PRIVATE);
+
+ { // Build constructor.
+ final MethodSpec.Builder builder = MethodSpec.constructorBuilder()
+ .addModifiers(Modifier.PUBLIC)
+ .addStatement("$T rnd = new $T()", Random.class, Random.class);
+
+ for (int i = 0; i < 3; i++)
+ builder.addStatement("col$L = rnd.nextLong()", i);
+
+ classBuilder.addMethod(builder.build());
+ }
+
+ final JavaFile javaFile = JavaFile.builder(packageName, classBuilder.build()).build();
+
+ final ClassLoader loader = MarshallerUtil.compileCode(javaFile, classes);
+
+ try {
+ return loader.loadClass(packageName + '.' + className);
+ }
+ catch (Exception ex) {
+ throw new IllegalStateException("Failed to compile/instantiate generated Serializer.", ex);
+ }
+ }
+
+ /**
* Test object.
*/
public static class TestObject {
@@ -413,7 +498,7 @@ public class JavaSerializerTest {
/**
* Test object with private constructor.
*/
- private static class PrivateTestObject {
+ public static class PrivateTestObject {
/**
* @return Random TestObject.
*/
@@ -431,7 +516,6 @@ public class JavaSerializerTest {
/**
* Private constructor.
*/
- @SuppressWarnings("RedundantNoArgConstructor")
private PrivateTestObject() {
}