Adds DI and SPI examples
This commit is contained in:
parent
9f120b6317
commit
e407698e84
11
di/pom.xml
Normal file
11
di/pom.xml
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
<parent>
|
||||||
|
<groupId>fr.gasser</groupId>
|
||||||
|
<artifactId>java-cookbook</artifactId>
|
||||||
|
<version>1.0-SNAPSHOT</version>
|
||||||
|
</parent>
|
||||||
|
<artifactId>di</artifactId>
|
||||||
|
</project>
|
11
di/src/main/java/ovh/gasser/di/InjectConstant.java
Normal file
11
di/src/main/java/ovh/gasser/di/InjectConstant.java
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
package ovh.gasser.di;
|
||||||
|
|
||||||
|
import java.lang.annotation.ElementType;
|
||||||
|
import java.lang.annotation.Retention;
|
||||||
|
import java.lang.annotation.RetentionPolicy;
|
||||||
|
import java.lang.annotation.Target;
|
||||||
|
|
||||||
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
@Target({ ElementType.FIELD })
|
||||||
|
public @interface InjectConstant {
|
||||||
|
}
|
18
di/src/main/java/ovh/gasser/di/InjectionUtils.java
Normal file
18
di/src/main/java/ovh/gasser/di/InjectionUtils.java
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
package ovh.gasser.di;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public interface InjectionUtils {
|
||||||
|
static void populateConstants(Class<?> clazz, Map<?, ?> values) {
|
||||||
|
Arrays.stream(clazz.getDeclaredFields())
|
||||||
|
.filter(field -> field.isAnnotationPresent(InjectConstant.class))
|
||||||
|
.forEach(field -> {
|
||||||
|
try {
|
||||||
|
field.set(null, values.get(field.getName()));
|
||||||
|
} catch (IllegalAccessException e) {
|
||||||
|
throw new RuntimeException("Unable to setup constant for field " + field.getName(), e);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
17
di/src/main/java/ovh/gasser/di/TestClass.java
Normal file
17
di/src/main/java/ovh/gasser/di/TestClass.java
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
package ovh.gasser.di;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public class TestClass {
|
||||||
|
@InjectConstant
|
||||||
|
public static String TEST;
|
||||||
|
|
||||||
|
static {
|
||||||
|
Map<String, String> values = Map.of("TEST", "Injected value for TEST");
|
||||||
|
InjectionUtils.populateConstants(TestClass.class, values);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
System.out.println(TEST);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,11 @@
|
|||||||
|
package ovh.gasser.translation;
|
||||||
|
|
||||||
|
import java.lang.annotation.ElementType;
|
||||||
|
import java.lang.annotation.Retention;
|
||||||
|
import java.lang.annotation.RetentionPolicy;
|
||||||
|
import java.lang.annotation.Target;
|
||||||
|
|
||||||
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
@Target({ ElementType.FIELD })
|
||||||
|
public @interface InjectTranslation {
|
||||||
|
}
|
50
di/src/main/java/ovh/gasser/translation/InjectionUtils.java
Normal file
50
di/src/main/java/ovh/gasser/translation/InjectionUtils.java
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
package ovh.gasser.translation;
|
||||||
|
|
||||||
|
import org.w3c.dom.Document;
|
||||||
|
|
||||||
|
import javax.xml.parsers.DocumentBuilder;
|
||||||
|
import javax.xml.parsers.DocumentBuilderFactory;
|
||||||
|
import javax.xml.xpath.*;
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
final class InjectionUtils {
|
||||||
|
private static final XPath xPath;
|
||||||
|
private static final Document document;
|
||||||
|
|
||||||
|
static {
|
||||||
|
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
|
||||||
|
try {
|
||||||
|
var resource = InjectionUtils.class.getResource("/translations.xml");
|
||||||
|
DocumentBuilder documentBuilder = dbf.newDocumentBuilder();
|
||||||
|
document = documentBuilder.parse(resource.getFile());
|
||||||
|
XPathFactory xpf = XPathFactory.newInstance();
|
||||||
|
xPath = xpf.newXPath();
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Private ctor to prevent instantiation
|
||||||
|
*/
|
||||||
|
private InjectionUtils() {
|
||||||
|
throw new IllegalStateException();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void populateTranslations(Class<?> clazz, String language) {
|
||||||
|
Arrays.stream(clazz.getDeclaredFields())
|
||||||
|
.filter(field -> field.isAnnotationPresent(InjectTranslation.class))
|
||||||
|
.forEach(field -> {
|
||||||
|
try {
|
||||||
|
String expression = String.format("/translations/string[@key='%s']/translation[@lang='%s']", field.getName(), language);
|
||||||
|
XPathExpression xPathExpression = xPath.compile(expression);
|
||||||
|
String s = (String) xPathExpression.evaluate(document, XPathConstants.STRING);
|
||||||
|
field.set(null, s);
|
||||||
|
} catch (IllegalAccessException e) {
|
||||||
|
throw new RuntimeException("Unable to setup constant for field " + field.getName(), e);
|
||||||
|
} catch (XPathExpressionException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
13
di/src/main/java/ovh/gasser/translation/Main.java
Normal file
13
di/src/main/java/ovh/gasser/translation/Main.java
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
package ovh.gasser.translation;
|
||||||
|
|
||||||
|
public class Main {
|
||||||
|
public static void main(String[] args) {
|
||||||
|
InjectionUtils.populateTranslations(TestClass.class, "DE");
|
||||||
|
System.out.println(TestClass.HELLO);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class TestClass {
|
||||||
|
@InjectTranslation
|
||||||
|
static String HELLO;
|
||||||
|
}
|
||||||
|
}
|
8
di/src/main/resources/translations.xml
Normal file
8
di/src/main/resources/translations.xml
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8" ?>
|
||||||
|
<translations>
|
||||||
|
<string key="HELLO">
|
||||||
|
<translation lang="EN">Hello</translation>
|
||||||
|
<translation lang="FR">Bonjour</translation>
|
||||||
|
<translation lang="DE">Guten tag</translation>
|
||||||
|
</string>
|
||||||
|
</translations>
|
@ -1,7 +1,7 @@
|
|||||||
package annotations.jsonserializer;
|
package annotations.jsonserializer;
|
||||||
|
|
||||||
class JsonSerializeException extends RuntimeException {
|
class JsonSerializeException extends RuntimeException {
|
||||||
JsonSerializeException(String message) {
|
public JsonSerializeException(String message, Throwable cause) {
|
||||||
super(message);
|
super(message, cause);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -21,7 +21,7 @@ class SerializableFieldExtractor {
|
|||||||
}
|
}
|
||||||
return jsonElements;
|
return jsonElements;
|
||||||
} catch (SecurityException | IllegalArgumentException | IllegalAccessException e) {
|
} catch (SecurityException | IllegalArgumentException | IllegalAccessException e) {
|
||||||
throw new JsonSerializeException(e.getMessage());
|
throw new JsonSerializeException("JSON serializing error", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -0,0 +1,39 @@
|
|||||||
|
package messagebroker.handlers;
|
||||||
|
|
||||||
|
import messagebroker.MessageHandlerContext;
|
||||||
|
import messagebroker.UnknownMessageFormatException;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
|
||||||
|
import static org.mockito.Mockito.*;
|
||||||
|
|
||||||
|
public class EchoMessageHandlerTest {
|
||||||
|
|
||||||
|
private final MessageHandlerContext context = mock(MessageHandlerContext.class);
|
||||||
|
private EchoMessageHandler messageHandler;
|
||||||
|
|
||||||
|
public EchoMessageHandlerTest() {
|
||||||
|
when(context.getOutputStream()).thenReturn(mock(OutputStream.class));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Before()
|
||||||
|
public void setUp() {
|
||||||
|
messageHandler = new EchoMessageHandler(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void shouldHandleEchoMessage() throws UnknownMessageFormatException, IOException {
|
||||||
|
var message = "ECHO Some message";
|
||||||
|
messageHandler.handleMessage(message);
|
||||||
|
verify(context.getOutputStream()).flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = UnknownMessageFormatException.class)
|
||||||
|
public void shouldThrowWhenMessageIsUnknown() throws UnknownMessageFormatException {
|
||||||
|
var message = "Bad message";
|
||||||
|
messageHandler.handleMessage(message);
|
||||||
|
}
|
||||||
|
}
|
2
pom.xml
2
pom.xml
@ -13,6 +13,8 @@
|
|||||||
<module>lang</module>
|
<module>lang</module>
|
||||||
<module>persistence</module>
|
<module>persistence</module>
|
||||||
<module>messaging</module>
|
<module>messaging</module>
|
||||||
|
<module>di</module>
|
||||||
|
<module>spi</module>
|
||||||
</modules>
|
</modules>
|
||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
|
15
spi/pom.xml
Normal file
15
spi/pom.xml
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xmlns="http://maven.apache.org/POM/4.0.0"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<parent>
|
||||||
|
<groupId>fr.gasser</groupId>
|
||||||
|
<artifactId>java-cookbook</artifactId>
|
||||||
|
<version>1.0-SNAPSHOT</version>
|
||||||
|
</parent>
|
||||||
|
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
<artifactId>spi</artifactId>
|
||||||
|
|
||||||
|
</project>
|
32
spi/src/main/java/ovh/gasser/spi/CommandProvider.java
Normal file
32
spi/src/main/java/ovh/gasser/spi/CommandProvider.java
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
package ovh.gasser.spi;
|
||||||
|
|
||||||
|
import ovh.gasser.spi.commands.Command;
|
||||||
|
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.ServiceLoader;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
public class CommandProvider {
|
||||||
|
private static CommandProvider instance = new CommandProvider();
|
||||||
|
|
||||||
|
private final ServiceLoader<Command> loader;
|
||||||
|
|
||||||
|
private CommandProvider() {
|
||||||
|
loader = ServiceLoader.load(Command.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static CommandProvider getInstance() {
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Stream<Command> getCommands() {
|
||||||
|
return loader.stream().map(ServiceLoader.Provider::get);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Optional<Command> getCommand(String commandId) {
|
||||||
|
return loader.stream()
|
||||||
|
.filter(commandProvider -> commandProvider.get().getId().equalsIgnoreCase(commandId))
|
||||||
|
.findFirst()
|
||||||
|
.map(ServiceLoader.Provider::get);
|
||||||
|
}
|
||||||
|
}
|
16
spi/src/main/java/ovh/gasser/spi/Main.java
Normal file
16
spi/src/main/java/ovh/gasser/spi/Main.java
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
package ovh.gasser.spi;
|
||||||
|
|
||||||
|
public class Main {
|
||||||
|
public static void main(String[] args) {
|
||||||
|
CommandProvider commandProvider = CommandProvider.getInstance();
|
||||||
|
// Execute all commands
|
||||||
|
commandProvider.getCommands()
|
||||||
|
.forEach(command -> System.out.println(command.execute("Hello")));
|
||||||
|
|
||||||
|
// Execute command with specific ID
|
||||||
|
String result = commandProvider.getCommand("reverse")
|
||||||
|
.map(command -> command.execute("Reverse command"))
|
||||||
|
.orElse("Unknown command");
|
||||||
|
System.out.println(result);
|
||||||
|
}
|
||||||
|
}
|
7
spi/src/main/java/ovh/gasser/spi/commands/Command.java
Normal file
7
spi/src/main/java/ovh/gasser/spi/commands/Command.java
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
package ovh.gasser.spi.commands;
|
||||||
|
|
||||||
|
public interface Command {
|
||||||
|
String getId();
|
||||||
|
|
||||||
|
String execute(String input);
|
||||||
|
}
|
14
spi/src/main/java/ovh/gasser/spi/commands/EchoCommand.java
Normal file
14
spi/src/main/java/ovh/gasser/spi/commands/EchoCommand.java
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
package ovh.gasser.spi.commands;
|
||||||
|
|
||||||
|
public class EchoCommand implements Command {
|
||||||
|
|
||||||
|
private static final String COMMAND_NAME = "echo";
|
||||||
|
|
||||||
|
public String getId() {
|
||||||
|
return COMMAND_NAME;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String execute(String input) {
|
||||||
|
return input;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,16 @@
|
|||||||
|
package ovh.gasser.spi.commands;
|
||||||
|
|
||||||
|
public class ReverseCommand implements Command {
|
||||||
|
|
||||||
|
private static final String COMMAND_NAME = "reverse";
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getId() {
|
||||||
|
return COMMAND_NAME;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String execute(String input) {
|
||||||
|
return new StringBuilder(input).reverse().toString();
|
||||||
|
}
|
||||||
|
}
|
16
spi/src/main/java/ovh/gasser/spi/commands/UpperCommand.java
Normal file
16
spi/src/main/java/ovh/gasser/spi/commands/UpperCommand.java
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
package ovh.gasser.spi.commands;
|
||||||
|
|
||||||
|
public class UpperCommand implements Command {
|
||||||
|
|
||||||
|
private static final String COMMAND_NAME = "upper";
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getId() {
|
||||||
|
return COMMAND_NAME;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String execute(String input) {
|
||||||
|
return input.toUpperCase();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,3 @@
|
|||||||
|
ovh.gasser.spi.commands.EchoCommand
|
||||||
|
ovh.gasser.spi.commands.UpperCommand
|
||||||
|
ovh.gasser.spi.commands.ReverseCommand
|
Loading…
Reference in New Issue
Block a user