Adds DI and SPI examples
This commit is contained in:
		
							
								
								
									
										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;
 | 
			
		||||
 | 
			
		||||
class JsonSerializeException extends RuntimeException {
 | 
			
		||||
    JsonSerializeException(String message) {
 | 
			
		||||
        super(message);
 | 
			
		||||
    public JsonSerializeException(String message, Throwable cause) {
 | 
			
		||||
        super(message, cause);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -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);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -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>persistence</module>
 | 
			
		||||
        <module>messaging</module>
 | 
			
		||||
        <module>di</module>
 | 
			
		||||
        <module>spi</module>
 | 
			
		||||
    </modules>
 | 
			
		||||
 | 
			
		||||
    <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
 | 
			
		||||
		Reference in New Issue
	
	Block a user