Added documentation, nexus OSS deployment settings.

This commit is contained in:
Andrew Lalis 2023-09-22 09:11:10 -04:00
parent 3fc0efca5f
commit 7890c2cd19
9 changed files with 201 additions and 57 deletions

View File

@ -1,41 +1,8 @@
# 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
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).
## Example

119
pom.xml
View File

@ -6,7 +6,7 @@
<groupId>com.andrewlalis</groupId>
<artifactId>record-net</artifactId>
<version>2.0.0</version>
<version>1.0.0-SNAPSHOT</version>
<name>Record-Net</name>
<description>A simple library for reading and writing records deterministically and efficiently.</description>
<url>https://github.com/andrewlalis/record-net</url>
@ -35,24 +35,121 @@
</dependency>
</dependencies>
<!-- Setup for deploying to GitHub packages with mvn deploy. -->
<distributionManagement>
<repository>
<id>github</id>
<name>Github record-net Apache Maven Packages</name>
<url>https://maven.pkg.github.com/andrewlalis/record-net</url>
</repository>
</distributionManagement>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<version>3.2.1</version>
<executions>
<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>
<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>
<licenses>
<license>
<name>MIT License</name>
<url>https://github.com/andrewlalis/record-net/blob/main/LICENSE</url>
<distribution>repo</distribution>
<url>https://www.opensource.org/licenses/mit-license.php</url>
</license>
</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>

View File

@ -6,6 +6,10 @@ import java.io.IOException;
import java.lang.reflect.Array;
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 {
private IOUtil() {}

View File

@ -3,7 +3,20 @@ package com.andrewlalis.record_net;
import java.lang.reflect.Constructor;
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) {
/**
* 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) {
if (!type.isRecord()) throw new IllegalArgumentException(type + " is not a record.");
RecordComponent[] c = type.getRecordComponents();
@ -18,6 +31,4 @@ record RecordInfo<T>(RecordComponent[] components, Constructor<T> constructor) {
throw new RuntimeException(e);
}
}
}

View File

@ -6,11 +6,21 @@ import java.util.HashMap;
import java.util.Map;
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 {
private final Map<Integer, Class<?>> messageTypes = new HashMap<>();
private final Map<Class<?>, Integer> messageTypeIds = 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) {
if (!type.isRecord()) throw new IllegalArgumentException("Only records are permitted.");
this.messageTypes.put(id, type);
@ -18,6 +28,20 @@ public class RecordMappedSerializer implements RecordSerializer {
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) {
return messageTypeIds.containsKey(type);
}
@ -62,7 +86,10 @@ public class RecordMappedSerializer implements RecordSerializer {
if (type.equals(UUID.class)) {
return IOUtil.readUUID(dIn);
}
return IOUtil.readPrimitive(type, dIn);
if (type.isPrimitive()) {
return IOUtil.readPrimitive(type, dIn);
}
throw new UnsupportedMessageTypeException(type);
}
@Override

View File

@ -4,7 +4,25 @@ import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
/**
* Defines the basic interface for serialization and deserialization of
* messages to and from streams.
* @see RecordMappedSerializer
*/
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;
/**
* 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;
}

View File

@ -1,8 +1,19 @@
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 {
/**
* The id of the message as it was received.
*/
public final int messageId;
/**
* Constructs the exception with a given id.
* @param messageId The id of the message.
*/
public UnknownMessageIdException(int messageId) {
super("Unknown record-net message id " + messageId);
this.messageId = messageId;

View File

@ -1,16 +1,22 @@
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 {
/**
* The type that's not supported.
*/
public Class<?> messageType;
public int messageId;
/**
* Constructs a new exception with the given type.
* @param messageType The unsupported type.
*/
public UnsupportedMessageTypeException(Class<?> messageType) {
super("The message type " + messageType.getSimpleName() + " is not supported.");
this.messageType = messageType;
}
public UnsupportedMessageTypeException(int messageId) {
super("The message with id " + messageId + " is not supported.");
this.messageId = messageId;
}
}

View File

@ -1,3 +1,6 @@
/**
* The record_net module definition.
*/
module com.andrewlalis.record_net {
exports com.andrewlalis.record_net;
}