T invoke(Class> targetClass, Method method, Object... args) {
+ Object constantPool = getConstantPool(targetClass);
+ T returnValue = null;
+ try {
+ returnValue = invokeMethod(true, constantPool, method, args);
+ } catch (Throwable e) {
+ logger.trace(e.getMessage());
+ }
+ return returnValue;
+ }
+
+ static Object getConstantPool(Class> targetClass) {
+ return invokeMethod(true, (Object) targetClass, "getConstantPool");
+ }
+
+ static Class> loadConstantPoolClass() {
+ ClassLoader classLoader = getSystemClassLoader();
+ Class> javaLangAccessClass = loadClass(classLoader, LEGACY_CONSTANT_POOL_CLASS_NAME);
+ return defaultIfNull(javaLangAccessClass, () -> loadClass(classLoader, CONSTANT_POOL_CLASS_NAME));
+ }
+
+ private ConstantPoolUtils() {
+ }
+}
\ No newline at end of file
diff --git a/microsphere-java-core/src/main/java/io/microsphere/invoke/MethodHandleUtils.java b/microsphere-java-core/src/main/java/io/microsphere/invoke/MethodHandleUtils.java
index 4a63b79f0..5d9872109 100644
--- a/microsphere-java-core/src/main/java/io/microsphere/invoke/MethodHandleUtils.java
+++ b/microsphere-java-core/src/main/java/io/microsphere/invoke/MethodHandleUtils.java
@@ -32,6 +32,7 @@
import static io.microsphere.collection.MapUtils.newConcurrentHashMap;
import static io.microsphere.invoke.MethodHandleUtils.LookupKey.buildKey;
+import static io.microsphere.invoke.MethodHandleUtils.LookupMode.ALL;
import static io.microsphere.invoke.MethodHandleUtils.LookupMode.getModes;
import static io.microsphere.invoke.MethodHandlesLookupUtils.NOT_FOUND_METHOD_HANDLE;
import static io.microsphere.invoke.MethodHandlesLookupUtils.findPublic;
@@ -291,7 +292,7 @@ static LookupKey buildKey(Class> requestedClass, int allowedModes) {
* @return non-null
*/
public static Lookup lookup(Class> requestedClass) {
- return lookup(requestedClass, LookupMode.ALL);
+ return lookup(requestedClass, ALL);
}
/**
@@ -348,7 +349,7 @@ protected static MethodHandle find(Class> requestedClass, String methodName, C
if (method == null) {
return NOT_FOUND_METHOD_HANDLE;
}
- if (isiCandidateMethod(method)) {
+ if (isCandidateMethod(method)) {
return findPublic(method, function);
}
Lookup lookup = lookup(requestedClass);
@@ -357,12 +358,12 @@ protected static MethodHandle find(Class> requestedClass, String methodName, C
private static Lookup newLookup(LookupKey key) {
if (lookupConstructor3 != null) {
- return newInstance(lookupConstructor3, key.requestedClass, key.requestedClass, key.allowedModes);
+ return newInstance(true, lookupConstructor3, key.requestedClass, key.requestedClass, key.allowedModes);
}
- return newInstance(lookupConstructor2, key.requestedClass, key.allowedModes);
+ return newInstance(true, lookupConstructor2, key.requestedClass, key.allowedModes);
}
- private static boolean isiCandidateMethod(Method method) {
+ private static boolean isCandidateMethod(Method method) {
return isPublic(method) && !isCallerSensitiveMethod(method);
}
diff --git a/microsphere-java-core/src/main/java/io/microsphere/invoke/MethodHandlesLookupUtils.java b/microsphere-java-core/src/main/java/io/microsphere/invoke/MethodHandlesLookupUtils.java
index ed3a4eb73..ff6ec9c72 100644
--- a/microsphere-java-core/src/main/java/io/microsphere/invoke/MethodHandlesLookupUtils.java
+++ b/microsphere-java-core/src/main/java/io/microsphere/invoke/MethodHandlesLookupUtils.java
@@ -22,6 +22,7 @@
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
+import java.lang.invoke.MethodHandles.Lookup;
import java.lang.invoke.MethodType;
import java.lang.reflect.Method;
@@ -33,7 +34,7 @@
import static java.lang.invoke.MethodType.methodType;
/**
- * Utilities class providing convenient methods for working with {@link MethodHandles.Lookup}.
+ * Utilities class providing convenient methods for working with {@link Lookup}.
*
* This class offers various static methods to simplify the process of obtaining and using
* method handles, particularly for public virtual and static methods. It serves as a central
@@ -66,12 +67,12 @@ public abstract class MethodHandlesLookupUtils implements Utils {
public static final MethodHandle NOT_FOUND_METHOD_HANDLE = null;
/**
- * The {@link MethodHandles.Lookup} for {@link MethodHandles#publicLookup()}
+ * The {@link Lookup} for {@link MethodHandles#publicLookup()}
*/
- public static final MethodHandles.Lookup PUBLIC_LOOKUP = publicLookup();
+ public static final Lookup PUBLIC_LOOKUP = publicLookup();
/**
- * The convenient method to find {@link MethodHandles.Lookup#findVirtual(Class, String, MethodType)} for public method
+ * The convenient method to find {@link Lookup#findVirtual(Class, String, MethodType)} for public method
*
* @param requestedClass the class to be looked up
* @param methodName the target method name
@@ -83,7 +84,7 @@ public static MethodHandle findPublicVirtual(Class> requestedClass, String met
}
/**
- * The convenient method to find {@link MethodHandles.Lookup#findStatic(Class, String, MethodType)} for public static method
+ * The convenient method to find {@link Lookup#findStatic(Class, String, MethodType)} for public static method
*
* @param requestedClass the class to be looked up
* @param methodName the target method name
@@ -95,22 +96,22 @@ public static MethodHandle findPublicStatic(Class> requestedClass, String meth
}
protected static MethodHandle findPublic(Class> requestedClass, String methodName, Class[] parameterTypes,
- ThrowableBiFunction function) {
+ ThrowableBiFunction function) {
return find(PUBLIC_LOOKUP, requestedClass, methodName, parameterTypes, function);
}
- protected static MethodHandle find(MethodHandles.Lookup lookup, Class> requestedClass, String methodName, Class[] parameterTypes,
- ThrowableBiFunction function) {
+ protected static MethodHandle find(Lookup lookup, Class> requestedClass, String methodName, Class[] parameterTypes,
+ ThrowableBiFunction function) {
Method method = findMethod(requestedClass, methodName, parameterTypes);
return find(lookup, method, function);
}
- protected static MethodHandle findPublic(Method method, ThrowableBiFunction function) {
+ protected static MethodHandle findPublic(Method method, ThrowableBiFunction function) {
return find(PUBLIC_LOOKUP, method, function);
}
- protected static MethodHandle find(MethodHandles.Lookup lookup, Method method,
- ThrowableBiFunction function) {
+ protected static MethodHandle find(Lookup lookup, Method method,
+ ThrowableBiFunction function) {
if (method == null) {
return NOT_FOUND_METHOD_HANDLE;
}
diff --git a/microsphere-java-core/src/main/java/io/microsphere/io/serializer/AbstractSerializer.java b/microsphere-java-core/src/main/java/io/microsphere/io/serializer/AbstractSerializer.java
new file mode 100644
index 000000000..4def99ed8
--- /dev/null
+++ b/microsphere-java-core/src/main/java/io/microsphere/io/serializer/AbstractSerializer.java
@@ -0,0 +1,138 @@
+package io.microsphere.io.serializer;
+
+import io.microsphere.annotation.Nonnull;
+import io.microsphere.io.IOUtils;
+import io.microsphere.reflect.JavaType;
+
+import java.io.IOException;
+
+import static io.microsphere.reflect.JavaType.from;
+import static io.microsphere.util.SizeUtils.UNBOUND_BYTES_SIZE;
+
+/**
+ * Convenience base class for {@link Serializer} and {@liink Deserializer} implementations that handles null-safety
+ * and fixed-length byte-array validation, delegating the actual encode/decode logic to
+ * {@link #doSerialize(Object)} and {@link #doDeserialize(byte[])}.
+ *
+ * The expected serialized byte-array length is determined by {@link #calcBytesLength()}.
+ * Sub-classes that always produce arrays of a fixed size (e.g. 4 bytes for {@link Integer})
+ * should override this method to return that size; those with variable-length output should
+ * return {@link IOUtils#UNBOUND_BYTES_SIZE}.
+ *
+ *
Example Usage
+ * {@code
+ * public class IntegerSerializer extends AbstractSerializer {
+ *
+ * public static final IntegerSerializer INTEGER_SERIALIZER = new IntegerSerializer();
+ *
+ * @Override
+ * protected int calcBytesLength() {
+ * return INTEGER_BYTES_LENGTH; // 4
+ * }
+ *
+ * @Override
+ * protected byte[] doSerialize(Integer value) {
+ * ByteBuffer buffer = ByteBuffer.allocate(INTEGER_BYTES_LENGTH);
+ * buffer.putInt(value);
+ * return buffer.array();
+ * }
+ *
+ * @Override
+ * protected Integer doDeserialize(byte[] bytes) {
+ * return ByteBuffer.wrap(bytes).getInt();
+ * }
+ * }
+ *
+ * byte[] bytes = INTEGER_SERIALIZER.serialize(42); // 4-byte big-endian int
+ * int value = INTEGER_SERIALIZER.deserialize(bytes); // 42
+ * }
+ *
+ * @param Serialized/Deserialized type
+ * @author Mercy
+ * @since 1.0.0
+ */
+public abstract class AbstractSerializer implements Serializer, Deserializer {
+
+ private final Class targetType;
+
+ private final int bytesLength;
+
+ /**
+ * Resolves the serializable type parameter {@code T} via reflection and pre-calculates
+ * the expected serialized byte-array length.
+ */
+ public AbstractSerializer() {
+ JavaType type = from(getClass()).as(AbstractSerializer.class).getGenericType(0);
+ this.targetType = type.toClass();
+ this.bytesLength = calcBytesLength();
+ }
+
+ @Override
+ public final byte[] serialize(T t) throws IOException {
+ // null compatible case
+ if (t == null) {
+ return null;
+ }
+ return doSerialize(t);
+ }
+
+ @Override
+ public final T deserialize(byte[] bytes) throws IOException {
+ // null compatible case
+ if (bytes == null) {
+ return null;
+ }
+
+ // Compatible byte array fixed case
+ if (bytesLength != UNBOUND_BYTES_SIZE && bytesLength != bytes.length) {
+ return null;
+ }
+
+ return doDeserialize(bytes);
+ }
+
+ /**
+ * Returns the target type {@code T} that this serializer/deserializer handles.
+ *
+ * @return the target type class
+ */
+ public final Class getTargetType() {
+ return targetType;
+ }
+
+ /**
+ * Returns the expected length of the serialized byte array, or {@link IOUtils#UNBOUND_BYTES_SIZE}
+ * if variable-length serialization is used.
+ *
+ * @return the fixed bytes length (e.g. {@code 4} for {@code Integer}), or {@code -1}
+ */
+ public int getBytesLength() {
+ return bytesLength;
+ }
+
+ /**
+ * Calculates the expected fixed serialized byte-array length.
+ * Sub-classes with a fixed-size representation must override this to return the correct size.
+ *
+ * @return the fixed byte length, or {@link IOUtils#UNBOUND_BYTES_SIZE} ({@code -1}) for variable-length
+ */
+ protected abstract int calcBytesLength();
+
+ /**
+ * Performs the actual serialization of a non-null {@code t} value.
+ *
+ * @param t the value to serialize; never {@code null}
+ * @return the serialized byte array; must not be {@code null}
+ * @throws IOException if serialization fails
+ */
+ protected abstract byte[] doSerialize(@Nonnull T t) throws IOException;
+
+ /**
+ * Performs the actual deserialization of a non-null {@code bytes} array.
+ *
+ * @param bytes the byte array to deserialize; never {@code null}
+ * @return the deserialized value
+ * @throws IOException if deserialization fails
+ */
+ protected abstract T doDeserialize(@Nonnull byte[] bytes) throws IOException;
+}
\ No newline at end of file
diff --git a/microsphere-java-core/src/main/java/io/microsphere/io/serializer/BooleanSerializer.java b/microsphere-java-core/src/main/java/io/microsphere/io/serializer/BooleanSerializer.java
new file mode 100644
index 000000000..8aee5fa13
--- /dev/null
+++ b/microsphere-java-core/src/main/java/io/microsphere/io/serializer/BooleanSerializer.java
@@ -0,0 +1,37 @@
+package io.microsphere.io.serializer;
+
+import static io.microsphere.util.SizeUtils.BOOLEAN_BYTES_SIZE;
+
+/**
+ * Java {@code boolean} or {@link Boolean} type {@link Serializer} and {@link Deserializer} Class
+ *
+ * @author Mercy
+ * @see AbstractSerializer
+ * @since 1.0.0
+ */
+public final class BooleanSerializer extends AbstractSerializer {
+
+ public static final BooleanSerializer BOOLEAN_SERIALIZER = new BooleanSerializer();
+
+ private static final byte TRUE_VALUE = 1;
+
+ private static final byte FALSE_VALUE = 0;
+
+ @Override
+ protected int calcBytesLength() {
+ return BOOLEAN_BYTES_SIZE;
+ }
+
+ @Override
+ protected byte[] doSerialize(Boolean booleanValue) {
+ byte byteValue = booleanValue ? TRUE_VALUE : FALSE_VALUE;
+ byte[] bytes = new byte[]{byteValue};
+ return bytes;
+ }
+
+ @Override
+ protected Boolean doDeserialize(byte[] bytes) {
+ byte byteValue = bytes[0];
+ return byteValue == TRUE_VALUE;
+ }
+}
\ No newline at end of file
diff --git a/microsphere-java-core/src/main/java/io/microsphere/io/serializer/ByteSerializer.java b/microsphere-java-core/src/main/java/io/microsphere/io/serializer/ByteSerializer.java
new file mode 100644
index 000000000..04be890e5
--- /dev/null
+++ b/microsphere-java-core/src/main/java/io/microsphere/io/serializer/ByteSerializer.java
@@ -0,0 +1,49 @@
+/*
+ * 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.microsphere.io.serializer;
+
+import java.io.IOException;
+
+import static io.microsphere.util.SizeUtils.BYTE_BYTES_SIZE;
+
+/**
+ * Java {@code byte} or {@link Byte} type {@link Serializer} and {@link Deserializer} Class
+ *
+ * @author Mercy
+ * @see AbstractSerializer
+ * @since 1.0.0
+ */
+public class ByteSerializer extends AbstractSerializer {
+
+ public static final ByteSerializer BYTE_SERIALIZER = new ByteSerializer();
+
+ @Override
+ protected int calcBytesLength() {
+ return BYTE_BYTES_SIZE;
+ }
+
+ @Override
+ protected byte[] doSerialize(Byte b) throws IOException {
+ return new byte[]{b};
+ }
+
+ @Override
+ protected Byte doDeserialize(byte[] bytes) throws IOException {
+ return bytes[0];
+ }
+}
diff --git a/microsphere-java-core/src/main/java/io/microsphere/io/serializer/CharacterSerializer.java b/microsphere-java-core/src/main/java/io/microsphere/io/serializer/CharacterSerializer.java
new file mode 100644
index 000000000..8c86c2baa
--- /dev/null
+++ b/microsphere-java-core/src/main/java/io/microsphere/io/serializer/CharacterSerializer.java
@@ -0,0 +1,52 @@
+/*
+ * 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.microsphere.io.serializer;
+
+import static io.microsphere.util.SizeUtils.CHAR_BYTES_SIZE;
+
+/**
+ * Java {@code char} or {@link Character} type {@link Serializer} and {@link Deserializer} Class
+ *
+ * @author Mercy
+ * @see AbstractSerializer
+ * @since 1.0.0
+ */
+public class CharacterSerializer extends AbstractSerializer {
+
+ public static final CharacterSerializer CHARACTER_SERIALIZER = new CharacterSerializer();
+
+ @Override
+ protected int calcBytesLength() {
+ return CHAR_BYTES_SIZE;
+ }
+
+ @Override
+ protected byte[] doSerialize(Character character) {
+ char c = character.charValue();
+ return new byte[]{
+ (byte) (c >>> 8), // High byte
+ (byte) c // Low byte
+ };
+ }
+
+ @Override
+ protected Character doDeserialize(byte[] bytes) {
+ char c = (char) ((bytes[0] << 8) | (bytes[1] & 0xFF));
+ return c;
+ }
+}
diff --git a/microsphere-java-core/src/main/java/io/microsphere/io/DefaultDeserializer.java b/microsphere-java-core/src/main/java/io/microsphere/io/serializer/DefaultDeserializer.java
similarity index 92%
rename from microsphere-java-core/src/main/java/io/microsphere/io/DefaultDeserializer.java
rename to microsphere-java-core/src/main/java/io/microsphere/io/serializer/DefaultDeserializer.java
index 19409d26d..7ddff69e7 100644
--- a/microsphere-java-core/src/main/java/io/microsphere/io/DefaultDeserializer.java
+++ b/microsphere-java-core/src/main/java/io/microsphere/io/serializer/DefaultDeserializer.java
@@ -14,7 +14,9 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package io.microsphere.io;
+package io.microsphere.io.serializer;
+
+import io.microsphere.io.FastByteArrayInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
@@ -48,7 +50,7 @@
*/
public class DefaultDeserializer implements Deserializer