diff --git a/nostr-java-base/src/main/java/nostr/base/json/EventJsonMapper.java b/nostr-java-base/src/main/java/nostr/base/json/EventJsonMapper.java new file mode 100644 index 00000000..b1638b56 --- /dev/null +++ b/nostr-java-base/src/main/java/nostr/base/json/EventJsonMapper.java @@ -0,0 +1,23 @@ +package nostr.base.json; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.json.JsonMapper; +import com.fasterxml.jackson.module.blackbird.BlackbirdModule; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; + +/** + * Provides access to the shared {@link ObjectMapper} configured for canonical Nostr event + * serialization and deserialization. + */ +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public final class EventJsonMapper { + + private static final ObjectMapper MAPPER = + JsonMapper.builder().addModule(new BlackbirdModule()).build(); + + /** Returns the shared {@link ObjectMapper} instance for Nostr events. */ + public static ObjectMapper mapper() { + return MAPPER; + } +} diff --git a/nostr-java-event/src/main/java/nostr/event/serializer/EventSerializer.java b/nostr-java-event/src/main/java/nostr/event/serializer/EventSerializer.java new file mode 100644 index 00000000..0085f0f1 --- /dev/null +++ b/nostr-java-event/src/main/java/nostr/event/serializer/EventSerializer.java @@ -0,0 +1,48 @@ +package nostr.event.serializer; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.ArrayNode; +import java.nio.charset.StandardCharsets; +import java.util.Optional; +import lombok.NonNull; +import lombok.experimental.UtilityClass; +import nostr.base.json.EventJsonMapper; +import nostr.event.impl.GenericEvent; +import nostr.util.NostrException; + +/** Utility methods for producing canonical NIP-01 event payloads. */ +@UtilityClass +public class EventSerializer { + + private static final ObjectMapper MAPPER = EventJsonMapper.mapper(); + + /** + * Serializes the provided {@link GenericEvent} to its canonical JSON representation following + * NIP-01. + * + * @param event the event to serialize + * @return the canonical JSON array representation as a string + * @throws NostrException if the event cannot be serialized + */ + public static String serializeToJson(@NonNull GenericEvent event) throws NostrException { + ArrayNode arrayNode = MAPPER.createArrayNode(); + arrayNode.add(0); + arrayNode.add(Optional.ofNullable(event.getPubKey()).map(Object::toString).orElse(null)); + arrayNode.add(event.getCreatedAt()); + arrayNode.add(event.getKind()); + arrayNode.add(MAPPER.valueToTree(event.getTags())); + arrayNode.add(event.getContent()); + + try { + return MAPPER.writeValueAsString(arrayNode); + } catch (JsonProcessingException e) { + throw new NostrException(e); + } + } + + /** Serializes the provided event to UTF-8 encoded bytes of the canonical JSON payload. */ + public static byte[] serializeToBytes(@NonNull GenericEvent event) throws NostrException { + return serializeToJson(event).getBytes(StandardCharsets.UTF_8); + } +}