Adds DI and SPI examples

This commit is contained in:
Thibaud Gasser 2020-03-15 18:59:33 +01:00
parent 9f120b6317
commit e407698e84
20 changed files with 302 additions and 3 deletions

11
di/pom.xml Normal file
View 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>

View 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 {
}

View 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);
}
});
}
}

View 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);
}
}

View File

@ -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 {
}

View 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);
}
});
}
}

View 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;
}
}

View 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>

View File

@ -1,7 +1,7 @@
package annotations.jsonserializer;
class JsonSerializeException extends RuntimeException {
JsonSerializeException(String message) {
super(message);
public JsonSerializeException(String message, Throwable cause) {
super(message, cause);
}
}

View File

@ -21,7 +21,7 @@ class SerializableFieldExtractor {
}
return jsonElements;
} catch (SecurityException | IllegalArgumentException | IllegalAccessException e) {
throw new JsonSerializeException(e.getMessage());
throw new JsonSerializeException("JSON serializing error", e);
}
}

View File

@ -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);
}
}

View File

@ -13,6 +13,8 @@
<module>lang</module>
<module>persistence</module>
<module>messaging</module>
<module>di</module>
<module>spi</module>
</modules>
<properties>

15
spi/pom.xml Normal file
View 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>

View 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);
}
}

View 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);
}
}

View File

@ -0,0 +1,7 @@
package ovh.gasser.spi.commands;
public interface Command {
String getId();
String execute(String input);
}

View 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;
}
}

View File

@ -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();
}
}

View 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();
}
}

View File

@ -0,0 +1,3 @@
ovh.gasser.spi.commands.EchoCommand
ovh.gasser.spi.commands.UpperCommand
ovh.gasser.spi.commands.ReverseCommand