Coder Social home page Coder Social logo

nostr-java's Introduction

nostr-java

Introducing the nostr-java library, a solution written in java for generating, signing, and publishing nostr events to relays.

Requirements

  • Maven
  • Java 19+

Usage

To use the library in your project, add the following dependency to your pom.xml file:

<dependency>
    <groupId>com.github.tcheeric.nostr-java</groupId>
    <artifactId>nostr-java-api</artifactId>
    <version>${nostr.java.version}</version>
</dependency>

I recommend having a look at the nostr-example module and the nostr-client project for a simple example on how to use the library.

Supported NIPs

The following NIPs are supported by the API out-of-the-box:

Dev Discussion Group:

  • Nostr Public Channel: nostr:nevent1qqszqdmxg26sehmnyrcu2ler8azz6wyj6fh0qg3ad5fnnm6xfqqvhzcppamhxue69uhkummnw3ezumt0d5pzpl7nwh45p66gvet2q28dhjpcyh6clux4cjsm5gh7waza9pzjnmgglv06ew

nostr-java's People

Contributors

avlo avatar devinbileck avatar guilhermegps avatar koalasat avatar kuiperanon avatar memory-of-snow avatar tcheeric avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

nostr-java's Issues

Implement NIP44

This requires changes in nostr.id.IdentityHelper.
(May need refactoring)

Private key generator

Why isn't it generating privkeys and pubkeys? Well, it's necessary to implement this feature.

Can you publish this library please? :0)

Hi there,

This is a lovely set of libs - so thank you for that! I would like to use them in the relay project I am working on. I can fork it and pull updates periodically but it would be much nicer if I could just pull the binaries from maven central or another repo.

One simple option is https://jitpack.io

  1. Change the groupId to start with com.github
  2. Include the following at the bottom of the parent pom:
    <repositories>
        <repository>
            <id>jitpack.io</id>
            <url>https://jitpack.io</url>
        </repository>
    </repositories>
  1. Create a release (tag) on Github periodically

That's it.

Change maven project's structure

What do you think about changing the structure of the project? Instead of have a multi-modules structure, we'd have just one module maven with many packages (to organize the code). It'll be easiest to integrate the code among the packages. Today we have a lot of problems with dependencies because maven can't have cyclic dependencies (you can read more about it here).

Something like that (without Spring, of course):
image

Just one pom.xml for whole project.
image

Could not transfer artifact com.tcheeric:nostr-schnorr:pom:0.1-SNAPSHOT

Hi there - this looks like a really useful collection of stuff for playing with Nostr in Javaland... so thank you for that!

Just having a problem building as the HEAD seems to be missing this shnorr dependency that I couldn't see on Github.

    <dependency>
        <groupId>${project.groupId}</groupId>
        <artifactId>nostr-schnorr</artifactId>
        <version>${project.version}</version>
    </dependency>

cheers! :0)

Remove unnecessary modules/classes/methods

  • The unmarshaller classes are completely irrelevant to the protocol and can be removed.
  • Same for the parser classes, they are now obsolete
  • That means we can get rid of nostr-types and nostr-json modules.

Reimplement NIP-03

NIP-03 has changed since it was last implemented. Update the code to take into account the changes made to the spec.

The java.util.NoSuchElementException occurs in the constructor of ResponseHandlerImpl.

Describe the bug
The java.util.NoSuchElementException occurs in the constructor of ResponseHandlerImpl.

To Reproduce

  1. Run NostrExamples.
    2.An exception occurs on the line 68 "private final static Client CLIENT = Client.getInstance(RELAYS);"

Expected behavior
The exception does not occur.

Additional context
Is it correct to have the expression "filter(ch -> !ch.getClass().isAnnotationPresent(DefaultHandler.class))" inside the constructor of ResponseHandlerImpl? Shouldn't it be "filter(ch -> ch.getClass().isAnnotationPresent(DefaultHandler.class))" instead?

FAILURE! - in nostr.test.event.EventTest testUnmarshallEvent

Filters kinds are encoded as array of String, instead of array of integers.

I believe this is because of
@JsonValue String Kind.toString()

This causes the following error:
testCreateTextNoteEvent Tests run: 7, Failures: 0, Errors: 1, Skipped: 0, Time elapsed: 0.613 s <<< FAILURE! - in nostr.test.event.EventTest testUnmarshallEvent Time elapsed: 0.108 s <<< ERROR! java.lang.ClassCastException: class nostr.types.values.impl.StringValue cannot be cast to class nostr.types.values.impl.NumberValue (nostr.types.values.impl.StringValue and nostr.types.values.impl.NumberValue are in unnamed module of loader 'app') at nostr.test.event.EventTest.testUnmarshallEvent(EventTest.java:209)

The parsing of List<String> failed from the message in ResponseHandlerImpl.java

Describe the bug
Even if the message is received successfully, parsing from the message to List fails in ResponseHandlerImpl.

Expected behavior
The message to be parsed into a List.

Additional context
The received message is a string surrounded by square brackets [], and it is not in JSON format, so it cannot be converted to String[] using objectMapper.readValue(message, String[].class).

Multiple filters per `REQ` request

Sorry if this came up before (did a search and found nothing).
I am trying to create multiple filters, nothing too complex..
e.g. (KIND 1 from Pubkey A) or (KIND 30 from Pubkey B) in a single subscription.

Shouldn't the ReqMessage have the ability to specify multiple Filters objects?

"Kind":0 Event failed.

Describe the bug
"Kind":0 Event failed and Failed to update profile.

To Reproduce
Steps to reproduce the behavior:
Run metaDataEvent() in NostrExamples.java

Expected behavior
Successfully updated profile.

"Causes and solutions"
The member variable profile in MetadataEvent is missing annotation "@JsonIgnore".
Add @JsonIgnore to profile in MetadataEvent.java.

java.lang.RuntimeException at nostr.ws.Connection.serverURI(Connection.java:102)

The error occurs occasionally when running the nostr.examples.NostrExamples main class in the java-nostr-examples maven module. The issue is reproducible with the code in the feature_bug_fixes branch

Jun 15, 2023 10:04:03 PM nostr.id.Client lambda$send$2
WARNING: null
java.util.concurrent.ExecutionException: java.lang.RuntimeException
	at java.base/java.util.concurrent.FutureTask.report(FutureTask.java:122)
	at java.base/java.util.concurrent.FutureTask.get(FutureTask.java:191)
	at nostr.id.Client.lambda$send$2(Client.java:106)
	at java.base/java.util.stream.ReferencePipeline$2$1.accept(ReferencePipeline.java:178)
	at java.base/java.util.HashMap$KeySpliterator.forEachRemaining(HashMap.java:1707)
	at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:509)
	at java.base/java.util.stream.ForEachOps$ForEachTask.compute(ForEachOps.java:290)
	at java.base/java.util.concurrent.CountedCompleter.exec(CountedCompleter.java:754)
	at java.base/java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:373)
	at java.base/java.util.concurrent.ForkJoinTask.invoke(ForkJoinTask.java:686)
	at java.base/java.util.stream.ForEachOps$ForEachOp.evaluateParallel(ForEachOps.java:159)
	at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateParallel(ForEachOps.java:173)
	at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:233)
	at java.base/java.util.stream.ReferencePipeline.forEach(ReferencePipeline.java:596)
	at nostr.id.Client.send(Client.java:112)
	at nostr.examples.NostrExamples.sendEncryptedDirectMessage(NostrExamples.java:267)
	at nostr.examples.NostrExamples.lambda$main$1(NostrExamples.java:107)
	at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:539)
	at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
	at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136)
	at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635)
	at java.base/java.lang.Thread.run(Thread.java:833)
Caused by: java.lang.RuntimeException
	at nostr.ws.Connection.serverURI(Connection.java:102)
	at nostr.id.Client.openRelay(Client.java:158)
	at nostr.id.Client.lambda$init$5(Client.java:174)
	... 4 more
Jun 15, 2023 10:04:03 PM nostr.ws.response.handler.provider.ResponseHandlerImpl <init>
WARNING: No custom command handler provided. Using default command handler
Jun 15, 2023 10:04:03 PM nostr.id.Client lambda$send$2
WARNING: null
java.util.concurrent.ExecutionException: java.lang.RuntimeException
	at java.base/java.util.concurrent.FutureTask.report(FutureTask.java:122)
	at java.base/java.util.concurrent.FutureTask.get(FutureTask.java:191)
	at nostr.id.Client.lambda$send$2(Client.java:106)
	at java.base/java.util.stream.ReferencePipeline$2$1.accept(ReferencePipeline.java:178)
	at java.base/java.util.HashMap$KeySpliterator.forEachRemaining(HashMap.java:1707)
	at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:509)
	at java.base/java.util.stream.ForEachOps$ForEachTask.compute(ForEachOps.java:290)
	at java.base/java.util.concurrent.CountedCompleter.exec(CountedCompleter.java:754)
	at java.base/java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:373)
	at java.base/java.util.concurrent.ForkJoinTask.invoke(ForkJoinTask.java:686)
	at java.base/java.util.stream.ForEachOps$ForEachOp.evaluateParallel(ForEachOps.java:159)
	at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateParallel(ForEachOps.java:173)
	at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:233)
	at java.base/java.util.stream.ReferencePipeline.forEach(ReferencePipeline.java:596)
	at nostr.id.Client.send(Client.java:112)
	at nostr.examples.NostrExamples.createChannel(NostrExamples.java:486)
	at nostr.examples.NostrExamples.sendChannelMessage(NostrExamples.java:524)
	at nostr.examples.NostrExamples.lambda$main$12(NostrExamples.java:195)
	at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:539)
	at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
	at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136)
	at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635)
	at java.base/java.lang.Thread.run(Thread.java:833)
Caused by: java.lang.RuntimeException
	at nostr.ws.Connection.serverURI(Connection.java:102)
	at nostr.id.Client.openRelay(Client.java:158)
	at nostr.id.Client.lambda$init$5(Client.java:174)
	... 4 more

NIP-13 Nonce mining

Nonce mining is slow on json object, on string is fast but on bytes is the fastest.
Have been trying to develop an nostr server, and looked at the event id mining.
Thus gave it a try as a unit test, and thought to share it as you may need equal like code;

	@Test
	public void testMining() throws Exception {
		Duration maxMining = Duration.ofSeconds(360);
		int maxDifficulty = (OctoTrust.KEY_LENGTH * 8) / 2; // is 128 thus 50% of bits are zero
		NoStrIdentity nid = new NoStrIdentity(NoStrIdentityPrivateKey.ofRandom());
		try (JsonReader reader = Json.createReader(new InputStreamReader(getClass().getResourceAsStream("note-text-simple.json")))) {
			NoStrEvent event = new NoStrEvent(reader.readObject());
			Assertions.assertTrue(NoStrEventSignature.verify(event));
			int testOffsetDifficulty = 10; // +12 from note-text-simple.json

			// use test public key and copy others
			NoStrEventPayload payload = new NoStrEventPayload(nid.getPublicKey(), event.getPayload().getCreatedAt(), event.getPayload().getKind(), event.getPayload().getTags(), event.getPayload().getContent());
			Optional<NoStrEventTag> nonceTagOpt = payload.findFirstByQName(NoStrImplEventTag.NONCE);
			if (nonceTagOpt.isEmpty()) {
				return; // no mining requested
			}
			// replace X NoStrEventTag impl or NoStrEventTagCustom or NoStrTagNonce with local tag for setter access
			NoStrTagNonce nonceTag = new NoStrTagNonce(Integer.parseInt(nonceTagOpt.get().getMetaArgument(NoStrImplTagNonce.DIFFICULTY).get()) + testOffsetDifficulty);
			int nonceTagIdx = payload.getTags().indexOf(nonceTagOpt.get());
			payload.getTags().set(nonceTagIdx, nonceTag);

			int targetDifficulty = nonceTag.getDifficulty();
			if (targetDifficulty > maxDifficulty) {
				throw new IllegalArgumentException("Target difficulty can't be larger than " + maxDifficulty);
			}
			int mineCnt = 0;
			byte[] eventId = null;
			int leadingZeroBits = 0;
			byte[] nowStr = Long.toString(payload.getCreatedAt().getEpochSecond()).getBytes(StandardCharsets.UTF_8);
			byte[] payloadStr = NoStrEventSignature.generateEventIdJsonString(payload).getBytes(StandardCharsets.UTF_8);
			int createdAtLength = nowStr.length;
			int createdAtIdx = indexOf(payloadStr, nowStr, indexOf(payloadStr, new byte[]{'\"'}, 5));
			int nonceProofIdx = indexOf(payloadStr, "\"nonce\"".getBytes(StandardCharsets.UTF_8), 0) + 9;// ["nonce","7539","12"]],
			int nonceProofLength = Integer.toString(nonceTag.getBearerProof()).getBytes(StandardCharsets.UTF_8).length;
			long createdAtTime = System.currentTimeMillis();
			long maxMiningTime = createdAtTime + maxMining.toMillis();
			MessageDigest sha256 = OctoTrustHash.sha256Algorithm();

			while (leadingZeroBits < targetDifficulty) {
				mineCnt++;
				createdAtTime = System.currentTimeMillis();
				if (createdAtTime > maxMiningTime) {
					throw new IllegalStateException("Mining resource limit exceeded");
				}
				long createdAtTimeSecs = createdAtTime / 1000;
				int createdAtTimeDigits = numDigits(createdAtTimeSecs);
				if (createdAtLength != createdAtTimeDigits) {
					createdAtLength = createdAtTimeDigits;
					payloadStr = growBySplit(payloadStr, createdAtIdx);
				}
				writeDigits(createdAtTimeSecs, createdAtTimeDigits, payloadStr, createdAtIdx);

				int nonceProofDigits = numDigits(mineCnt);
				if (nonceProofLength != nonceProofDigits) {
					nonceProofLength = nonceProofDigits;
					payloadStr = growBySplit(payloadStr, nonceProofIdx);
				}
				writeDigits(mineCnt, nonceProofDigits, payloadStr, nonceProofIdx);

				eventId = sha256.digest(payloadStr);
				leadingZeroBits = 0;
				for (int i = 0; i < eventId.length; i++) {
					int step = eventId[i] & 0xFF; // force unsigned
					if (step == 0) {
						leadingZeroBits += 8;
						continue;
					}
					leadingZeroBits += Integer.numberOfLeadingZeros(step) - 24;
					break;
				}
			}
			payload.setCreatedAt(Instant.ofEpochMilli(createdAtTime));
			nonceTag.setBearerProof(mineCnt);

			NoStrEvent eventMined = NoStrEventSignature.sign(payload, nid.getPrivateKey(), eventId);

			System.out.println("idOrg=" + event.getId().getHex());
			System.out.println("idHex=" + eventMined.getId().getHex());
			System.out.println("idStr=" + NoStrEventSignature.generateEventIdJsonString(payload));
			System.out.println("leadZero=" + leadingZeroBits);
			System.out.println("mineCnt=" + mineCnt);
			System.out.println("idStrHex=" + OctoBitFormat.HEX.fromBytes(NoStrEventSignature.generateEventIdJsonString(payload).getBytes(StandardCharsets.UTF_8)));
			System.out.println("idStrArr=" + OctoBitFormat.HEX.fromBytes(payloadStr));

			Assertions.assertTrue(NoStrEventSignature.verify(eventMined));
			Assertions.assertEquals("" + mineCnt, eventMined.getPayload().findFirstByQName("nonce").get().getMetaArgument(0).get());
			Assertions.assertEquals("" + targetDifficulty, eventMined.getPayload().findFirstByQName("nonce").get().getMetaArgument(1).get());
		}
	}

	public byte[] growBySplit(byte[] src, int splitIdx) {
		byte[] result = new byte[src.length + 1];
		System.arraycopy(src, 0, result, 0, splitIdx);
		System.arraycopy(src, splitIdx + 1, result, splitIdx + 2, src.length - splitIdx - 1);
		return result;
	}
	
	public void writeDigits(long value, int digits, byte[] target, int off) {
		int i = digits - 1;
		while (value > 0) {
			target[i+off] = (byte) ((value % 10) + '0');
			value /= 10;
			i--;
		}
	}

	public int numDigits(long n) {
		return (int) Math.log10(n) + 1;
	}
	
	public int indexOf(byte[] source, byte[] target, int fromIndex) {
		return indexOf(source, 0, source.length, target, 0, target.length, fromIndex);
	}

	public int indexOf(byte[] source, int sourceOffset, int sourceCount, byte[] target, int targetOffset, int targetCount, int fromIndex) {
		if (fromIndex >= sourceCount) {
			return (targetCount == 0 ? sourceCount : -1);
		}
		if (fromIndex < 0) {
			fromIndex = 0;
		}
		if (targetCount == 0) {
			return fromIndex;
		}
		byte first = target[targetOffset];
		int max = sourceOffset + (sourceCount - targetCount);
		for (int i = sourceOffset + fromIndex; i <= max; i++) {
			if (source[i] != first) { // search first
				while (++i <= max && source[i] != first) {
					;
				}
			}
			if (i <= max) { // search left over
				int j = i + 1;
				int end = j + targetCount - 1;
				for (int k = targetOffset + 1; j < end && source[j] == target[k]; j++, k++) {
					;
				}
				if (j == end) {
					return i - sourceOffset;
				}
			}
		}
		return -1;
	}

The RelayInformationDocument class inside the Relay class is using member names that do not match the JSON.

Describe the bug
The RelayInformationDocument class inside the Relay class is using member names that do not match the JSON.

To Reproduce
Steps to reproduce the behavior:

  1. Run NostrExamples.
  2. The console displays "UnrecognizedPropertyException: Unrecognized field "supported_nips" (class nostr.base.Relay$RelayInformationDocument), not marked as ignorable (11 known properties: "contact", "pubkey", "software", "version", "limitation", "name", "description", "fees", "paymentsUrl", "supportedNipExtensions", "supportedNips")".

Additional context
In the JSON, the correct names to be used are "supported_nips", "supported_nip_extensions", and "payments_url" instead of "supportedNips", "supportedNipExtensions", and "paymentsUrl".

Use jackson API to decode json (un-marshalling)

  • InternetIdentifierMetadataEvent.setContent()
  • Nip05Validator.getPublicKey()
  • Connection.updateRelayMetadata()
  • Move the Nip05Validator functionality to nostr-util module, either as a class or as a static method within the NostrUtil class
  • more ?...

Is the restriction on the profile name appropriate?

Describe
Regarding the profile name, a pattern match is being performed with "\w[\w-]+\w" in validate() in MetadataEvent.java
Is this restriction unnecessary?

Additional context
In"NIP-01," it is only specified as "name: " without any restrictions regarding patterns or character types.

Client.send() not sending messages (?)

When I call the Client.send() from my client app, it doesn't send the message to the relay. It appears it never enters the forEach() section of the parallel stream defined in the method.

In my example below, I am trying to submit a REQ-message containing a filter to extract NIP-4 messages sent to a specific pubkey.

--- exec-maven-plugin:3.1.0:exec (default-cli) @ nostr-bot-client ---
SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".
SLF4J: Defaulting to no-operation (NOP) logger implementation
SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.

Apr 17, 2023 10:42:57 AM nostr.bot.job.NostrJob execute
INFO: Executing job: group1.NostrBotJob executing at 17/04/2023, 10:42,fired by: group1.NostrBotTrigger

Apr 17, 2023 10:42:57 AM nostr.bot.job.impl.AbstractPublisher lambda$publish$0
INFO: Filtering event since 1,681,724,455

Apr 17, 2023 10:42:57 AM nostr.bot.job.impl.AbstractPublisher lambda$publish$0
INFO: Filters: Filters(events=null, authors=null, kinds=BaseList(list=[4]), referencedEvents=null, referencePubKeys=BaseList(list=[f6a04a16b1fb3b4bf40838dacc7f8bd4d46b60d3c9e2a4915877f9a2eac8e323]), since=1681724455, until=null, limit=null, genericTagQueryList=null)

Apr 17, 2023 10:42:57 AM nostr.bot.job.impl.AbstractPublisher lambda$publish$0
INFO: Sending message ReqMessage(super=GenericMessage(command=REQ, attributes=[], nip=1), subscriptionId=nostr-bot, filters=Filters(events=null, authors=null, kinds=BaseList(list=[4]), referencedEvents=null, referencePubKeys=BaseList(list=[f6a04a16b1fb3b4bf40838dacc7f8bd4d46b60d3c9e2a4915877f9a2eac8e323]), since=1681724455, until=null, limit=null, genericTagQueryList=null))

Apr 17, 2023 10:42:57 AM nostr.bot.util.BotUtil storeLongToFile
INFO: Storing value 1,681,724,577 to file...

Apr 17, 2023 10:42:59 AM nostr.ws.handler.BaseHandler process
INFO: process

When connecting to certain relays, there is a failure in converting to RelayInformationDocument.

Describe
When connected to certain relays,
there is an item in RelayInformation that is not specified in NIP-11 called "id," causing a failure in converting it to Relay.RelayInformationDocument.

Additional context
The relay that is using nostr-rs-relay returns an item called "id" in RelayInformation.
I couldn't determine whether nostr-java or nostr-rs-relay is at fault.

https://github.com/nostr-protocol/nips/blob/master/11.md

NIP-42 - Relay Authentication

Branch: feature/NIP42_Issue_80

  • Fix auth errors ["OK","274a1363221092f3b15de2a81ebe3b6e6473464c9ac064621443cabda05e97a1",false,"restricted: authentication error: Invalid AUTH message"] from relay ws://localhost:5555
  • Implement CLOSED command.
  • Test authentication after the CLOSED handler with auth-required: warning message

When using the "e" tag on the "feature/feature_bug_fixes" branch, an exception occurs if the marker string is in lowercase.

To Reproduce
Steps to reproduce the behavior:
execute the following test.

package nostr.test.event;

import nostr.event.impl.GenericMessage;
import nostr.event.json.codec.BaseMessageDecoder;
import nostr.util.NostrException;
import org.junit.jupiter.api.Test;

public class DecodeTest {

    @Test
    public void decodeTest() throws NostrException {

        String json = "[" +
                "\"EVENT\"," +
                "\"temp20230627\"," +
                "{" +
                    "\"id\":\"28f2fc030e335d061f0b9d03ce0e2c7d1253e6fadb15d89bd47379a96b2c861a\"," +
                    "\"kind\":1," +
                    "\"pubkey\":\"2bed79f81439ff794cf5ac5f7bff9121e257f399829e472c7a14d3e86fe76984\"," +
                    "\"created_at\":1687765220," +
                    "\"content\":\"手順書が間違ってたら作業者は無理だな\"," +
                    "\"tags\":[" +
                        "[\"e\",\"494001ac0c8af2a10f60f23538e5b35d3cdacb8e1cc956fe7a16dfa5cbfc4346\",\"\",\"root\"]," +
                        "[\"p\",\"2bed79f81439ff794cf5ac5f7bff9121e257f399829e472c7a14d3e86fe76984\"]" +
                    "]," +
                    "\"sig\":\"86f25c161fec51b9e441bdb2c09095d5f8b92fdce66cb80d9ef09fad6ce53eaa14c5e16787c42f5404905536e43ebec0e463aee819378a4acbe412c533e60546\"" +
                "}]";

        BaseMessageDecoder decoder = new BaseMessageDecoder(json);
        GenericMessage message = decoder.decode();

    }

}

Expected behavior
It is expected to generate a 'GenericMessage'

The actual result.
The following exception occurred.

java.lang.IllegalArgumentException: No enum constant nostr.event.Marker.root (through reference chain: nostr.event.impl.GenericEvent["tags"]->java.util.ArrayList[0])

	at com.fasterxml.jackson.databind.ObjectMapper._convert(ObjectMapper.java:4449)
	at com.fasterxml.jackson.databind.ObjectMapper.convertValue(ObjectMapper.java:4390)
	at nostr.event.json.codec.BaseMessageDecoder.decode(BaseMessageDecoder.java:79)
	at nostr.test.event.DecodeTest.decodeTest(DecodeTest.java:30)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.base/java.lang.reflect.Method.invoke(Method.java:568)
	at org.junit.platform.commons.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:727)
	at org.junit.jupiter.engine.execution.MethodInvocation.proceed(MethodInvocation.java:60)
	at org.junit.jupiter.engine.execution.InvocationInterceptorChain$ValidatingInvocation.proceed(InvocationInterceptorChain.java:131)
	at org.junit.jupiter.engine.extension.TimeoutExtension.intercept(TimeoutExtension.java:156)
	at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestableMethod(TimeoutExtension.java:147)
	at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestMethod(TimeoutExtension.java:86)
	at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker$ReflectiveInterceptorCall.lambda$ofVoidMethod$0(InterceptingExecutableInvoker.java:103)
	at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker.lambda$invoke$0(InterceptingExecutableInvoker.java:93)
	at org.junit.jupiter.engine.execution.InvocationInterceptorChain$InterceptedInvocation.proceed(InvocationInterceptorChain.java:106)
	at org.junit.jupiter.engine.execution.InvocationInterceptorChain.proceed(InvocationInterceptorChain.java:64)
	at org.junit.jupiter.engine.execution.InvocationInterceptorChain.chainAndInvoke(InvocationInterceptorChain.java:45)
	at org.junit.jupiter.engine.execution.InvocationInterceptorChain.invoke(InvocationInterceptorChain.java:37)
	at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker.invoke(InterceptingExecutableInvoker.java:92)
	at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker.invoke(InterceptingExecutableInvoker.java:86)
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$invokeTestMethod$7(TestMethodTestDescriptor.java:217)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeTestMethod(TestMethodTestDescriptor.java:213)
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:138)
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:68)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:151)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141)
	at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95)
	at java.base/java.util.ArrayList.forEach(ArrayList.java:1511)
	at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:41)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:155)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141)
	at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95)
	at java.base/java.util.ArrayList.forEach(ArrayList.java:1511)
	at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:41)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:155)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141)
	at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95)
	at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.submit(SameThreadHierarchicalTestExecutorService.java:35)
	at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:57)
	at org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:54)
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:147)
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:127)
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:90)
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.lambda$execute$0(EngineExecutionOrchestrator.java:55)
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.withInterceptedStreams(EngineExecutionOrchestrator.java:102)
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:54)
	at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:114)
	at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:86)
	at org.junit.platform.launcher.core.DefaultLauncherSession$DelegatingLauncher.execute(DefaultLauncherSession.java:86)
	at org.junit.platform.launcher.core.SessionPerRequestLauncher.execute(SessionPerRequestLauncher.java:53)
	at com.intellij.junit5.JUnit5IdeaTestRunner.startRunnerWithArgs(JUnit5IdeaTestRunner.java:57)
	at com.intellij.rt.junit.IdeaTestRunner$Repeater$1.execute(IdeaTestRunner.java:38)
	at com.intellij.rt.execution.junit.TestsRepeater.repeat(TestsRepeater.java:11)
	at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:35)
	at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:232)
	at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:55)
Caused by: com.fasterxml.jackson.databind.JsonMappingException: No enum constant nostr.event.Marker.root (through reference chain: nostr.event.impl.GenericEvent["tags"]->java.util.ArrayList[0])
	at com.fasterxml.jackson.databind.JsonMappingException.wrapWithPath(JsonMappingException.java:402)
	at com.fasterxml.jackson.databind.JsonMappingException.wrapWithPath(JsonMappingException.java:373)
	at com.fasterxml.jackson.databind.deser.std.CollectionDeserializer._deserializeFromArray(CollectionDeserializer.java:375)
	at com.fasterxml.jackson.databind.deser.std.CollectionDeserializer.deserialize(CollectionDeserializer.java:244)
	at com.fasterxml.jackson.databind.deser.std.CollectionDeserializer.deserialize(CollectionDeserializer.java:28)
	at com.fasterxml.jackson.databind.deser.impl.MethodProperty.deserializeAndSet(MethodProperty.java:129)
	at com.fasterxml.jackson.databind.deser.BeanDeserializer.vanillaDeserialize(BeanDeserializer.java:314)
	at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:177)
	at com.fasterxml.jackson.databind.ObjectMapper._convert(ObjectMapper.java:4444)
	... 73 more
Caused by: java.lang.IllegalArgumentException: No enum constant nostr.event.Marker.root
	at java.base/java.lang.Enum.valueOf(Enum.java:273)
	at nostr.event.Marker.valueOf(Marker.java:8)
	at nostr.event.json.deserializer.TagDeserializer.deserialize(TagDeserializer.java:86)
	at nostr.event.json.deserializer.TagDeserializer.deserialize(TagDeserializer.java:19)
	at com.fasterxml.jackson.databind.deser.std.CollectionDeserializer._deserializeFromArray(CollectionDeserializer.java:359)
	... 79 more

Additional context
The cause is that the Enum constants are in uppercase, while the JSON markers are in lowercase.

java.lang.NullPointerException: Cannot invoke "String.equals(Object)" because the return value of "java.net.URI.getScheme()" is null

Apr 06, 2023 2:43:59 AM nostr.id.Client updateRelayInformation
SEVERE: null
java.lang.NullPointerException: Cannot invoke "String.equals(Object)" because the return value of "java.net.URI.getScheme()" is null
at nostr.ws.Connection.connect(Connection.java:114)
at nostr.ws.Connection.(Connection.java:68)
at nostr.id.Client.updateRelayInformation(Client.java:142)
at nostr.id.Client.openRelay(Client.java:117)
at nostr.id.Client.lambda$init$4(Client.java:126)
at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635)
at java.base/java.lang.Thread.run(Thread.java:833)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.