Added documentation, nexus OSS deployment settings.
This commit is contained in:
parent
3fc0efca5f
commit
7890c2cd19
41
README.md
41
README.md
|
@ -1,41 +1,8 @@
|
||||||
# record-net
|
# record-net
|
||||||
Simple, performant message library for Java, using records.
|
Simple, performant message library for Java, using records. It allows you to
|
||||||
|
serialize and deserialize records and their contents for use in network or
|
||||||
|
filesystem IO.
|
||||||
|
|
||||||
record-net gives you the advantages of reflection, without the runtime costs. By registering message types before starting your work, record-net is able to generate custom serializers and deserializers for all registered message types, which translates to read and write speeds that are nearly equivalent to directly writing bytes to a stream.
|
|
||||||
|
|
||||||
Here's an example of how you can use record-net:
|
|
||||||
|
|
||||||
```java
|
## Example
|
||||||
import com.andrewlalis.record_net.Message;
|
|
||||||
import com.andrewlalis.record_net.impl.TypeMappedSerializer;
|
|
||||||
|
|
||||||
import java.io.ByteArrayOutputStream;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.net.Socket;
|
|
||||||
|
|
||||||
class Example {
|
|
||||||
record ChatMessage(
|
|
||||||
long timestamp,
|
|
||||||
String username,
|
|
||||||
String msg
|
|
||||||
) implements Message {
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void main(String[] args) throws IOException {
|
|
||||||
var ser = new TypeMappedSerializer();
|
|
||||||
ser.registerType(1, ChatMessage.class);
|
|
||||||
var socket = new Socket("127.0.0.1", 8081);
|
|
||||||
var bOut = new ByteArrayOutputStream();
|
|
||||||
var msg = new ChatMessage(
|
|
||||||
System.currentTimeMillis(),
|
|
||||||
"andrew",
|
|
||||||
"Hello world!"
|
|
||||||
);
|
|
||||||
ser.writeMessage(msg, socket.getOutputStream());
|
|
||||||
ChatMessage response = (ChatMessage) ser.readMessage(socket.getInputStream());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## Get record-net
|
|
||||||
This project is published as a package on GitHub. You can view available packages [here](https://github.com/andrewlalis/record-net/packages). Alternatively, [you can get this project on jitpack.io](https://jitpack.io/#andrewlalis/record-net).
|
|
||||||
|
|
119
pom.xml
119
pom.xml
|
@ -6,7 +6,7 @@
|
||||||
|
|
||||||
<groupId>com.andrewlalis</groupId>
|
<groupId>com.andrewlalis</groupId>
|
||||||
<artifactId>record-net</artifactId>
|
<artifactId>record-net</artifactId>
|
||||||
<version>2.0.0</version>
|
<version>1.0.0-SNAPSHOT</version>
|
||||||
<name>Record-Net</name>
|
<name>Record-Net</name>
|
||||||
<description>A simple library for reading and writing records deterministically and efficiently.</description>
|
<description>A simple library for reading and writing records deterministically and efficiently.</description>
|
||||||
<url>https://github.com/andrewlalis/record-net</url>
|
<url>https://github.com/andrewlalis/record-net</url>
|
||||||
|
@ -35,24 +35,121 @@
|
||||||
</dependency>
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
<!-- Setup for deploying to GitHub packages with mvn deploy. -->
|
<build>
|
||||||
<distributionManagement>
|
<plugins>
|
||||||
<repository>
|
<plugin>
|
||||||
<id>github</id>
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
<name>Github record-net Apache Maven Packages</name>
|
<artifactId>maven-source-plugin</artifactId>
|
||||||
<url>https://maven.pkg.github.com/andrewlalis/record-net</url>
|
<version>3.2.1</version>
|
||||||
</repository>
|
<executions>
|
||||||
</distributionManagement>
|
<execution>
|
||||||
|
<id>attach-sources</id>
|
||||||
|
<goals>
|
||||||
|
<goal>jar-no-fork</goal>
|
||||||
|
</goals>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-javadoc-plugin</artifactId>
|
||||||
|
<version>3.3.1</version>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<id>attach-javadocs</id>
|
||||||
|
<goals>
|
||||||
|
<goal>jar</goal>
|
||||||
|
</goals>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-gpg-plugin</artifactId>
|
||||||
|
<version>3.1.0</version>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<id>sign-artifacts</id>
|
||||||
|
<phase>verify</phase>
|
||||||
|
<goals>
|
||||||
|
<goal>sign</goal>
|
||||||
|
</goals>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>net.ju-n.maven.plugins</groupId>
|
||||||
|
<artifactId>checksum-maven-plugin</artifactId>
|
||||||
|
<version>1.4</version>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<id>checksum-maven-plugin-files</id>
|
||||||
|
<phase>verify</phase>
|
||||||
|
<goals>
|
||||||
|
<goal>files</goal>
|
||||||
|
</goals>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
<configuration>
|
||||||
|
<fileSets>
|
||||||
|
<fileSet>
|
||||||
|
<directory>${project.build.directory}</directory>
|
||||||
|
<includes>
|
||||||
|
<include>*.pom</include>
|
||||||
|
<include>*.jar</include>
|
||||||
|
</includes>
|
||||||
|
</fileSet>
|
||||||
|
</fileSets>
|
||||||
|
<algorithms>
|
||||||
|
<algorithm>SHA-1</algorithm>
|
||||||
|
<algorithm>MD5</algorithm>
|
||||||
|
<algorithm>SHA-256</algorithm>
|
||||||
|
<algorithm>SHA-512</algorithm>
|
||||||
|
</algorithms>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.sonatype.plugins</groupId>
|
||||||
|
<artifactId>nexus-staging-maven-plugin</artifactId>
|
||||||
|
<version>1.6.13</version>
|
||||||
|
<extensions>true</extensions>
|
||||||
|
<configuration>
|
||||||
|
<serverId>ossrh</serverId>
|
||||||
|
<nexusUrl>https://s01.oss.sonatype.org</nexusUrl>
|
||||||
|
<autoReleaseAfterClose>false</autoReleaseAfterClose>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
|
||||||
<scm>
|
<scm>
|
||||||
<url>https://github.com/andrewlalis/record-net</url>
|
<url>https://github.com/andrewlalis/record-net</url>
|
||||||
|
<connection>scm:git:git://github.com/andrewlalis/record-net.git</connection>
|
||||||
|
<developerConnection>scm:git:ssh://github.com:andrewlalis/record-net.git</developerConnection>
|
||||||
</scm>
|
</scm>
|
||||||
|
|
||||||
<licenses>
|
<licenses>
|
||||||
<license>
|
<license>
|
||||||
<name>MIT License</name>
|
<name>MIT License</name>
|
||||||
<url>https://github.com/andrewlalis/record-net/blob/main/LICENSE</url>
|
<url>https://www.opensource.org/licenses/mit-license.php</url>
|
||||||
<distribution>repo</distribution>
|
|
||||||
</license>
|
</license>
|
||||||
</licenses>
|
</licenses>
|
||||||
|
|
||||||
|
<developers>
|
||||||
|
<developer>
|
||||||
|
<name>Andrew Lalis</name>
|
||||||
|
<email>andrewlalisofficial@gmail.com</email>
|
||||||
|
</developer>
|
||||||
|
</developers>
|
||||||
|
|
||||||
|
<distributionManagement>
|
||||||
|
<snapshotRepository>
|
||||||
|
<id>ossrh</id>
|
||||||
|
<url>https://s01.oss.sonatype.org/content/repositories/snapshots</url>
|
||||||
|
</snapshotRepository>
|
||||||
|
<repository>
|
||||||
|
<id>ossrh</id>
|
||||||
|
<url>https://s01.oss.sonatype.org/service/local/staging/deploy/maven2/</url>
|
||||||
|
</repository>
|
||||||
|
</distributionManagement>
|
||||||
</project>
|
</project>
|
|
@ -6,6 +6,10 @@ import java.io.IOException;
|
||||||
import java.lang.reflect.Array;
|
import java.lang.reflect.Array;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A utility class that contains functions for IO operations on certain data
|
||||||
|
* types. It cannot be instantiated; use its static methods only.
|
||||||
|
*/
|
||||||
public final class IOUtil {
|
public final class IOUtil {
|
||||||
private IOUtil() {}
|
private IOUtil() {}
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,20 @@ package com.andrewlalis.record_net;
|
||||||
import java.lang.reflect.Constructor;
|
import java.lang.reflect.Constructor;
|
||||||
import java.lang.reflect.RecordComponent;
|
import java.lang.reflect.RecordComponent;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A collection of the information that's needed about a record in order to
|
||||||
|
* serialize and deserialize it at runtime.
|
||||||
|
* @param components The record's ordered array of components.
|
||||||
|
* @param constructor The canonical constructor for the record.
|
||||||
|
* @param <T> The type of the record.
|
||||||
|
*/
|
||||||
record RecordInfo<T>(RecordComponent[] components, Constructor<T> constructor) {
|
record RecordInfo<T>(RecordComponent[] components, Constructor<T> constructor) {
|
||||||
|
/**
|
||||||
|
* Prepares an instance of RecordInfo for a given record class.
|
||||||
|
* @param type The record class.
|
||||||
|
* @return The RecordInfo object.
|
||||||
|
* @param <T> The type of the record.
|
||||||
|
*/
|
||||||
public static <T> RecordInfo<T> forType(Class<T> type) {
|
public static <T> RecordInfo<T> forType(Class<T> type) {
|
||||||
if (!type.isRecord()) throw new IllegalArgumentException(type + " is not a record.");
|
if (!type.isRecord()) throw new IllegalArgumentException(type + " is not a record.");
|
||||||
RecordComponent[] c = type.getRecordComponents();
|
RecordComponent[] c = type.getRecordComponents();
|
||||||
|
@ -18,6 +31,4 @@ record RecordInfo<T>(RecordComponent[] components, Constructor<T> constructor) {
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,11 +6,21 @@ import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The default {@link RecordSerializer} implementation that performs
|
||||||
|
* serialization and deserialization using a set of pre-registered, known
|
||||||
|
* record types.
|
||||||
|
*/
|
||||||
public class RecordMappedSerializer implements RecordSerializer {
|
public class RecordMappedSerializer implements RecordSerializer {
|
||||||
private final Map<Integer, Class<?>> messageTypes = new HashMap<>();
|
private final Map<Integer, Class<?>> messageTypes = new HashMap<>();
|
||||||
private final Map<Class<?>, Integer> messageTypeIds = new HashMap<>();
|
private final Map<Class<?>, Integer> messageTypeIds = new HashMap<>();
|
||||||
private final Map<Class<?>, RecordInfo<?>> messageRecordInfo = new HashMap<>();
|
private final Map<Class<?>, RecordInfo<?>> messageRecordInfo = new HashMap<>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registers a new record class to this serializer.
|
||||||
|
* @param id The id to assign to this type.
|
||||||
|
* @param type The record class.
|
||||||
|
*/
|
||||||
public void registerType(int id, Class<?> type) {
|
public void registerType(int id, Class<?> type) {
|
||||||
if (!type.isRecord()) throw new IllegalArgumentException("Only records are permitted.");
|
if (!type.isRecord()) throw new IllegalArgumentException("Only records are permitted.");
|
||||||
this.messageTypes.put(id, type);
|
this.messageTypes.put(id, type);
|
||||||
|
@ -18,6 +28,20 @@ public class RecordMappedSerializer implements RecordSerializer {
|
||||||
this.messageRecordInfo.put(type, RecordInfo.forType(type));
|
this.messageRecordInfo.put(type, RecordInfo.forType(type));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registers a new record class to this serializer, using the class' hash
|
||||||
|
* code as its id.
|
||||||
|
* @param type The record class.
|
||||||
|
*/
|
||||||
|
public void registerType(Class<?> type) {
|
||||||
|
this.registerType(type.hashCode(), type);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if a certain class has been registered for use with this serializer.
|
||||||
|
* @param type The type to check.
|
||||||
|
* @return True if the type is registered and may be used, or false otherwise.
|
||||||
|
*/
|
||||||
public boolean isTypeSupported(Class<?> type) {
|
public boolean isTypeSupported(Class<?> type) {
|
||||||
return messageTypeIds.containsKey(type);
|
return messageTypeIds.containsKey(type);
|
||||||
}
|
}
|
||||||
|
@ -62,8 +86,11 @@ public class RecordMappedSerializer implements RecordSerializer {
|
||||||
if (type.equals(UUID.class)) {
|
if (type.equals(UUID.class)) {
|
||||||
return IOUtil.readUUID(dIn);
|
return IOUtil.readUUID(dIn);
|
||||||
}
|
}
|
||||||
|
if (type.isPrimitive()) {
|
||||||
return IOUtil.readPrimitive(type, dIn);
|
return IOUtil.readPrimitive(type, dIn);
|
||||||
}
|
}
|
||||||
|
throw new UnsupportedMessageTypeException(type);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void writeMessage(Object msg, OutputStream out) throws IOException {
|
public void writeMessage(Object msg, OutputStream out) throws IOException {
|
||||||
|
|
|
@ -4,7 +4,25 @@ import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Defines the basic interface for serialization and deserialization of
|
||||||
|
* messages to and from streams.
|
||||||
|
* @see RecordMappedSerializer
|
||||||
|
*/
|
||||||
public interface RecordSerializer {
|
public interface RecordSerializer {
|
||||||
|
/**
|
||||||
|
* Reads a message from an input stream.
|
||||||
|
* @param in The input stream to read from.
|
||||||
|
* @return The object that was read.
|
||||||
|
* @throws IOException If an error occurs.
|
||||||
|
*/
|
||||||
Object readMessage(InputStream in) throws IOException;
|
Object readMessage(InputStream in) throws IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Writes a message to an output stream.
|
||||||
|
* @param msg The message to write.
|
||||||
|
* @param out The output stream to write to.
|
||||||
|
* @throws IOException If an error occurs.
|
||||||
|
*/
|
||||||
void writeMessage(Object msg, OutputStream out) throws IOException;
|
void writeMessage(Object msg, OutputStream out) throws IOException;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,19 @@
|
||||||
package com.andrewlalis.record_net;
|
package com.andrewlalis.record_net;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An exception that's thrown when a {@link RecordSerializer} reads a message
|
||||||
|
* whose id is unknown (not previously registered with the serializer).
|
||||||
|
*/
|
||||||
public class UnknownMessageIdException extends RuntimeException {
|
public class UnknownMessageIdException extends RuntimeException {
|
||||||
|
/**
|
||||||
|
* The id of the message as it was received.
|
||||||
|
*/
|
||||||
public final int messageId;
|
public final int messageId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs the exception with a given id.
|
||||||
|
* @param messageId The id of the message.
|
||||||
|
*/
|
||||||
public UnknownMessageIdException(int messageId) {
|
public UnknownMessageIdException(int messageId) {
|
||||||
super("Unknown record-net message id " + messageId);
|
super("Unknown record-net message id " + messageId);
|
||||||
this.messageId = messageId;
|
this.messageId = messageId;
|
||||||
|
|
|
@ -1,16 +1,22 @@
|
||||||
package com.andrewlalis.record_net;
|
package com.andrewlalis.record_net;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An exception that's thrown when attempting to serialize or deserialize an
|
||||||
|
* unsupported type. Unsupported types are any complex types not registered
|
||||||
|
* with a serializer, or unsupported by {@link IOUtil}.
|
||||||
|
*/
|
||||||
public class UnsupportedMessageTypeException extends RuntimeException {
|
public class UnsupportedMessageTypeException extends RuntimeException {
|
||||||
|
/**
|
||||||
|
* The type that's not supported.
|
||||||
|
*/
|
||||||
public Class<?> messageType;
|
public Class<?> messageType;
|
||||||
public int messageId;
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a new exception with the given type.
|
||||||
|
* @param messageType The unsupported type.
|
||||||
|
*/
|
||||||
public UnsupportedMessageTypeException(Class<?> messageType) {
|
public UnsupportedMessageTypeException(Class<?> messageType) {
|
||||||
super("The message type " + messageType.getSimpleName() + " is not supported.");
|
super("The message type " + messageType.getSimpleName() + " is not supported.");
|
||||||
this.messageType = messageType;
|
this.messageType = messageType;
|
||||||
}
|
}
|
||||||
|
|
||||||
public UnsupportedMessageTypeException(int messageId) {
|
|
||||||
super("The message with id " + messageId + " is not supported.");
|
|
||||||
this.messageId = messageId;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,6 @@
|
||||||
|
/**
|
||||||
|
* The record_net module definition.
|
||||||
|
*/
|
||||||
module com.andrewlalis.record_net {
|
module com.andrewlalis.record_net {
|
||||||
exports com.andrewlalis.record_net;
|
exports com.andrewlalis.record_net;
|
||||||
}
|
}
|
Loading…
Reference in New Issue