Skip to content

Commit

Permalink
Improve docs and examples
Browse files Browse the repository at this point in the history
  • Loading branch information
charphi committed Jan 30, 2024
1 parent 7636dd1 commit 34765dd
Show file tree
Hide file tree
Showing 11 changed files with 126 additions and 27 deletions.
28 changes: 27 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ The `@ServiceDefinition` annotation **defines a service usage and generates a sp
- checks coherence of service use in modules if `module-info.java` is available
- allows use of [custom service loader](#custom-service-loader)
- allows [batch loading](#batch-loading) of providers
- allows [identification](#provider-identity) of providers

**Limitations:**
- does not support [type inspection before instantiation](https://github.com/nbbrd/java-service-util/issues/13)
Expand Down Expand Up @@ -327,6 +328,29 @@ for (String file : files) {
}
```

### Provider identity

In some cases, you may need to identify the providers. This can be done by using the `@ServiceId` annotation.

```java
@ServiceDefinition(quantifier = Quantifier.MULTIPLE, batch = true)
public interface HashAlgorithm {

@ServiceId(pattern = ServiceId.SCREAMING_KEBAB_CASE)
String getName();

String hashToHex(byte[] input);

static void main(String[] args) {
HashAlgorithmLoader.load().stream()
.filter(algo -> algo.getName().equals("SHA-256"))
.findFirst()
.ifPresent(algo -> System.out.println(algo.hashToHex("hello".getBytes(UTF_8))));
}
}
```
_See [java-service-examples/src/main/java/nbbrd/service/examples/HashAlgorithm.java](java-service-examples/src/main/java/nbbrd/service/examples/HashAlgorithm.java)_

## Setup

```xml
Expand Down Expand Up @@ -373,4 +397,6 @@ Alternate setup if the IDE doesn't detect the processor:
## Related work
- [NetBeans Lookup](https://search.maven.org/search?q=g:org.netbeans.api%20AND%20a:org-openide-util-lookup&core=gav)
- [Google AutoServive](https://www.baeldung.com/google-autoservice)
- [Google AutoService](https://www.baeldung.com/google-autoservice)
- [TOOListicon SPI-Annotation-Processor](https://github.com/toolisticon/SPI-Annotation-Processor)
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
package nbbrd.service.examples;

import nbbrd.service.Quantifier;
import nbbrd.service.ServiceDefinition;
import nbbrd.service.ServiceId;
import nbbrd.service.ServiceProvider;

import java.math.BigInteger;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.Security;
import java.util.Locale;
import java.util.stream.Stream;

import static java.nio.charset.StandardCharsets.UTF_8;

@ServiceDefinition(quantifier = Quantifier.MULTIPLE, batch = true)
public interface HashAlgorithm {

@ServiceId(pattern = ServiceId.SCREAMING_KEBAB_CASE)
String getName();

String hashToHex(byte[] input);

static void main(String[] args) {
HashAlgorithmLoader.load().stream()
.filter(algo -> algo.getName().equals("SHA-256"))
.findFirst()
.ifPresent(algo -> System.out.println(algo.hashToHex("hello".getBytes(UTF_8))));
}

@ServiceProvider
class MessageDigestBridge implements HashAlgorithmBatch {

@Override
public Stream<HashAlgorithm> getProviders() {
return Security.getAlgorithms("MessageDigest")
.stream()
.map(MessageDigestAdapter::new);
}
}

class MessageDigestAdapter implements HashAlgorithm {

private final String name;

public MessageDigestAdapter(String name) {
this.name = name;
}

@Override
public String getName() {
return name;
}

@Override
public String hashToHex(byte[] input) {
return bytesToHex(getThreadUnsafeInstance().digest(input));
}

private MessageDigest getThreadUnsafeInstance() {
try {
return MessageDigest.getInstance(name);
} catch (NoSuchAlgorithmException ex) {
throw new RuntimeException(ex);
}
}

private static String bytesToHex(byte[] hash) {
return String.format(Locale.ROOT, "%0" + (hash.length << 1) + "x", new BigInteger(1, hash));
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -463,14 +463,14 @@ public void testNonComparableSorter() {
class ServiceIdTest {

@Test
public void testValidIds() {
assertThat(compile(forResource("definition/Ids.java")))
public void testNestedClass() {
assertThat(compile(forResource("definition/TestIdNestedClass.java")))
.has(succeededWithoutWarnings());
}

@Test
public void testLostId() {
JavaFileObject file = forResource("definition/LostId.java");
public void testLost() {
JavaFileObject file = forResource("definition/TestIdLost.java");

assertThat(compile(file))
.has(failed())
Expand All @@ -482,8 +482,8 @@ public void testLostId() {
}

@Test
public void testStaticId() {
JavaFileObject file = forResource("definition/StaticId.java");
public void testStaticMethod() {
JavaFileObject file = forResource("definition/TestIdStaticMethod.java");

assertThat(compile(file))
.has(failed())
Expand All @@ -495,8 +495,8 @@ public void testStaticId() {
}

@Test
public void testNoArgId() {
JavaFileObject file = forResource("definition/NoArgId.java");
public void testNoArg() {
JavaFileObject file = forResource("definition/TestIdNoArg.java");

assertThat(compile(file))
.has(failed())
Expand All @@ -508,8 +508,8 @@ public void testNoArgId() {
}

@Test
public void testNonStringId() {
JavaFileObject file = forResource("definition/NonStringId.java");
public void testNonString() {
JavaFileObject file = forResource("definition/TestIdNonString.java");

assertThat(compile(file))
.has(failed())
Expand All @@ -521,7 +521,7 @@ public void testNonStringId() {
}

@Test
public void testIdUniqueness() {
public void testUniqueness() {
JavaFileObject file = forResource("definition/TestIdUniqueness.java");

assertThat(compile(file))
Expand All @@ -534,34 +534,34 @@ public void testIdUniqueness() {
}

@Test
public void testIdWithEmptyPattern() {
JavaFileObject file = forResource("definition/TestIdWithEmptyPattern.java");
public void testEmptyPattern() {
JavaFileObject file = forResource("definition/TestIdEmptyPattern.java");

assertThat(compile(file))
.has(succeededWithoutWarnings())
.extracting(Compilation::generatedSourceFiles, JAVA_FILE_OBJECTS)
.singleElement()
.has(sourceFileNamed("definition", "TestIdWithEmptyPatternLoader.java"))
.has(sourceFileNamed("definition", "TestIdEmptyPatternLoader.java"))
.extracting(Compilations::contentsAsUtf8String, STRING)
.doesNotContain("public static final Pattern ID_PATTERN");
}

@Test
public void testIdWithValidPattern() {
JavaFileObject file = forResource("definition/TestIdWithValidPattern.java");
public void testWithValidPattern() {
JavaFileObject file = forResource("definition/TestIdValidPattern.java");

assertThat(compile(file))
.has(succeededWithoutWarnings())
.extracting(Compilation::generatedSourceFiles, JAVA_FILE_OBJECTS)
.singleElement()
.has(sourceFileNamed("definition", "TestIdWithValidPatternLoader.java"))
.has(sourceFileNamed("definition", "TestIdValidPatternLoader.java"))
.extracting(Compilations::contentsAsUtf8String, STRING)
.contains("public static final Pattern ID_PATTERN = Pattern.compile(\"^[A-Z0-9]+(?:_[A-Z0-9]+)*$\");");
}

@Test
public void testIdWithInvalidPattern() {
JavaFileObject file = forResource("definition/TestIdWithInvalidPattern.java");
public void testInvalidPattern() {
JavaFileObject file = forResource("definition/TestIdInvalidPattern.java");

assertThat(compile(file))
.has(failed())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import nbbrd.service.ServiceId;

@ServiceDefinition
interface TestIdWithEmptyPattern {
interface TestIdEmptyPattern {

@ServiceId( pattern = "" )
String getName();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import nbbrd.service.ServiceId;

@ServiceDefinition
interface TestIdWithInvalidPattern {
interface TestIdInvalidPattern {

@ServiceId( pattern = "***" )
String getName();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import nbbrd.service.ServiceDefinition;
import nbbrd.service.ServiceId;

class Ids {
class TestIdNestedClass {

@ServiceDefinition
interface SimpleId {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import nbbrd.service.ServiceId;

@ServiceDefinition
interface NoArgId {
interface TestIdNoArg {

@ServiceId
String getName(String arg);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import nbbrd.service.ServiceId;

@ServiceDefinition
interface NonStringId {
interface TestIdNonString {

@ServiceId
Object getName();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import nbbrd.service.ServiceId;

@ServiceDefinition
interface StaticId {
interface TestIdStaticMethod {

@ServiceId
static String getName() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import nbbrd.service.ServiceId;

@ServiceDefinition
interface TestIdWithValidPattern {
interface TestIdValidPattern {

@ServiceId( pattern = ServiceId.SCREAMING_SNAKE_CASE )
String getName();
Expand Down

0 comments on commit 34765dd

Please sign in to comment.