Let's consider the following simplified Resource hierarchy:
public abstract class Resource {
static public boolean accepts(String resource);
}
public class AudioResource extends Resource {
static public boolean accepts(String resource) {
//Check if we can proceed this resource as audio
//Some complex logic there ...
}
}
public class VideoResource extends Resource {
static public boolean accepts(String resource) {
//Check if we can proceed this resource as video
//Another complex logic there
}
}
Resource has dozens subclasses and number grows. Each sub-resource:
has some logic to determine if it accepts resource or not. E.g. it may parse resource URL with regexp or something;
is not singleton by design;
Now, we want to create a factory which iterates through all available subclasses and creates one which accepts resource (checks it using the accepts method).
Something like this (let's suppose for a moment that Java has static methods polymorphism):
public class ResourceFactory {
private static List<Class<Resource>> registry;
{
//Populate registry once on start
}
public static Resource createResource(String resource) {
for (Class<Resource> clazz : registry) {
if (clazz.accepts(resource))
return clazz.createInstance(resource);
}
}
}
Unfortunately (or not?), Java doesn't support polymorphic static methods. Considering that, what are the possible ways to design Resource and ResourceFactory?
You could use:
public interface Resource {
// some methods
}
public interface ResourceFactory {
boolean acceptsResource(String resource);
Resource createResource(String resource) throws UnsupportedResourceException;
}
public final MultiResourceFactory implements ResourceFactory{
private static final ServiceLoader<ResourceFactory > resourceFactoryLoader
= ServiceLoader.load(ResourceFactory .class);
private static final MultiResourceFactory INSTANCE;
private MultiResourceFactory(){
}
public static MultiResourceFactory getInstance(){
if (INSTANCE == null){
INSTANCE = new MultiResourceFactory();
}
return INSTANCE;
}
#Override
public boolean acceptsResource(String resource){
for (ResourceFactory resourceFactory : resourceFactoryLoader) {
if (resourceFactory.acceptsResource(resource)){
return true;
}
}
return false;
}
#Override
public Resource createResource(String resource) throws UnsupportedResourceException{
for (ResourceFactory resourceFactory : resourceFactoryLoader) {
if (resourceFactory.acceptsResource(resource)){
return resourceFactory.createResource(resource);
}
}
throw new UnsupportedResourceException(resource);
}
See ServiceLoader for how to register the factories:
http://docs.oracle.com/javase/6/docs/api/java/util/ServiceLoader.html
Note: the code is untested
Related
Guice newbie here, with a complicated scenario.
My company has a large number of constants of a given type (let's call them Thingy) that belong to different teams and are maintained in different parts of our application. However, we need to have a central registry that knows about all of them (let's call this the ThingyService). I am writing a base module that teams can either extend or install, with the purpose of allowing a team to register their Thingys, and giving them access to the ThingyService. This module takes as parameter a list of classes from which I can extract the Thingy constants, this part is working fine.
What I don't understand is how I can a) make each module know about each other module's list of Thingys and b) how I can create my ThingyService as a singleton that contains all of my Thingys. I have experimented with shared static state and with ThreadLocals, but I keep either breaking tests or breaking my main (play) application. In my naive understanding of Guice, I think I need a MultiBinder for the Thingys, but I don't see how I can share that between modules. Here's what I'd like to do:
class ThingyModule extends AbstractModule{
final Set<Class<?>> myThingyClasses; // this is populated in the constructor
private Set<Thingy> extractThingiesFromThingyClasses(){
// I have this working
}
#Provides #Singleton ThingyService thingyService(
Set<Thingy> thingys // all thingys, from all such modules
){
return new ThingyService(thingys);
}
protected void configure(){
extractThingiesFromThingyClasses().forEach(thingy->
// bind thingy to a global MultiBinder?
);
}
}
How can I make my ThingyService unique and global, with all the Thingys from the entire application? Note: I don't necessarily need my Thingys to be managed by Guice, the only place I need them is in ThingyService. Also, this is a play / scala application if that makes a difference, but my ThingyModule code lives in a library written in Java.
It turns out I omitted one important detail, Thingy has a type parameter, it's actually Thingy<T>, and that's the reason it didn't work before. By cheating and registering Thingy as raw type, and then also injecting it as raw type, I got it to work.
Here is a complete working example using JUnit 5 and AssertJ:
class ThingyModuleTest {
static class Thingy<T>{
private final T value;
Thingy(final T value) {this.value = value;}
#Override public boolean equals(final Object o) {
if (this == o) { return true; }
if (o == null || getClass() != o.getClass()) { return false; }
final Thingy<?> thingy = (Thingy<?>) o; return Objects.equals(value, thingy.value); }
#Override public int hashCode() { return Objects.hash(value); }
}
#Singleton
static class ThingyService{
final Set<Thingy<?>> thingies;
#SuppressWarnings({"unchecked", "rawtypes"}) #Inject
ThingyService(Set<Thingy> thingies) {
this.thingies = ImmutableSet.copyOf((Set)thingies);
}
public Set<Thingy<?>> getThingies() { return thingies; }
}
abstract static class ThingyModule extends AbstractModule {
private final Set<Class<?>> classesToScan;
public ThingyModule(Class<?>... classes) {
this.classesToScan = ImmutableSet.copyOf(classes);
}
private Set<Thingy<?>> scanForThingies(){
return classesToScan.stream()
.flatMap(c-> Arrays.stream(c.getDeclaredFields()))
.filter(f->f.getType().isAssignableFrom(Thingy.class))
.filter(f-> Modifier.isStatic(f.getModifiers())&&Modifier.isFinal(f.getModifiers()))
.map(this::readThingy)
.filter(Optional::isPresent)
.map(Optional::get)
.collect(Collectors.toSet());
}
#SuppressWarnings("unchecked")
private Optional<Thingy<?>> readThingy(final Field field) {
try{
field.setAccessible(true);
return Optional.ofNullable(field.get(null))
.filter(Thingy.class::isInstance)
.map(Thingy.class::cast);
} catch (IllegalAccessException e) { return Optional.empty(); }
}
#Override protected void configure() {
bind(ThingyService.class);
#SuppressWarnings("rawtypes") Multibinder<Thingy> multibinder = Multibinder.newSetBinder(binder(), Thingy.class);
scanForThingies().forEach(thingy -> multibinder.addBinding().toInstance(thingy));
}
}
static class ThingyModule1 extends ThingyModule {
public ThingyModule1() { super(Thingies1.class); }
static class Thingies1{
static final Thingy<Boolean> BooleanThingy = new Thingy<>(true);
static final Thingy<Integer> IntThingy = new Thingy<>(123);
}
}
static class ThingyModule2 extends ThingyModule {
public ThingyModule2() { super(Thingies2.class); }
static class Thingies2{
static final Thingy<String> StringThingy = new Thingy<>("hello");
static final Thingy<Long> LongThingy = new Thingy<>(123L);
}
}
#Test void validateThingyService() {
ThingyService thingyService = Guice.createInjector(new ThingyModule1(), new ThingyModule2())
.getProvider(ThingyService.class)
.get();
assertThat(thingyService).isNotNull()
.extracting(ts -> ImmutableList.copyOf(ts.getThingies()))
.asList()
.containsExactlyInAnyOrder(BooleanThingy, IntThingy, StringThingy, LongThingy);
}
}
I will mark this answer as accepted until somebody else provides a more idiomatic one.
I have set qualifier name from properties file as isomessage.qualifier=isoMessageMember1:
public class BankBancsConnectImpl implements BankBancsConnect{
#Autowired
#Resource(name="${isomessage.qualifier}")
private Iso8583Message iso8583Message;
public BancsConnectTransferComp getFundTransfer(IpsDcBatchDetail ipsDcBatchDetail) {
bancsxfr = iso8583Message.getFundTransfer(bancsxfr);
}
}
The value of ${isomessage.qualifier} is static as it is defined in the properties file. However i want it to be dynamic and get it's value from database based on certain condition. For instance i have multiple implementation of Iso8583Message (member wise) and has to call respective class of member id that is currently logged in. Please guide me to achieve this in the best and java spring way.
And my implementation class will look like this:
#Service("isoMessageMember1")
public class Iso8583MessageEBLImpl implements Iso8583Message{
public BancsConnectTransferComp getFundTransfer(BancsConnectTransferComp bancsxfr) throws Exception {
...
}
You can use Condition instead Qualifier if you are using Spring4+.
First, you need a ConfigDAO which read the qualifier name which you
need from database.
public class ConfigDAO {
public static String readFromDataSource() {
return " ";
}
}
Suppose there are two implemetions of Iso8583Message, you can
create two Condition objects.
IsoMessageMember1_Condition
public class IsoMessageMember1_Condition implements Condition {
#Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
String qualifier = ConfigDAO.readFromDataSource();
if (qualifier.equals("IsoMessageMember1_Condition")) {
return true;
} else {
return false;
}
}
}
IsoMessageMember2_Condition
public class IsoMessageMember2_Condition implements Condition {
#Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
String qualifier = ConfigDAO.readFromDataSource();
if (qualifier.equals("IsoMessageMember2_Condition")) {
return true;
} else {
return false;
}
}
}
Return different implemetion according to condition in config class.
#Configuration
public class MessageConfiguration {
#Bean(name = "iso8583Message")
#Conditional(IsoMessageMember1_Condition.class)
public Iso8583Message isoMessageMember1() {
return new Iso8583MessageEBLImpl();
}
#Bean(name = "iso8583Message")
#Conditional(IsoMessageMember2_Condition.class)
public Iso8583Message isoMessageMember2() {
return new OtherMessageEBLImpl();
}
}
Remove the #Qulifier and #Autowire annotations which you do not need anymore, you can retrieve the message from context every time you use it.
public class BankBancsConnectImpl implements BankBancsConnect{
private Iso8583Message iso8583Message;
public BancsConnectTransferComp getFundTransfer(IpsDcBatchDetail ipsDcBatchDetail) {
iso8583Message = (Iso8583Message)context.getBean("iso8583Message");
bancsxfr = iso8583Message.getFundTransfer(bancsxfr);
}
}
In spring it is possible to autowire the application context, and retrieve any bean based on its name.
For example, your interface signature similar to the below syntax
public interface Iso8583Message {
public String getFundDetails(String uniqueId);
}
and 2 different implementations follow below format
#Service("iso8583-message1")
public class Iso8583MessageImpl1 implements Iso8583Message {
#Override
public String getFundDetails(String uniqueId) {
return "Iso8583MessageImpl1 details ";
}
}
and
#Service("iso8583-message2")
public class Iso8583MessageImpl2 implements Iso8583Message {
#Override
public String getFundDetails(String uniqueId) {
return "Iso8583MessageImpl2 details ";
}
}
We can retrieve the beans as follows
public class BankBancsConnectImpl implements BankBancsConnect{
#Autowired
private ApplicationContext applicationContext;
public BancsConnectTransferComp getFundTransfer(IpsDcBatchDetail
ipsDcBatchDetail) {
//for retrieving 1st implementation
Iso8583Message iso8583Message=applicationContext.getBean("iso8583-message1", Iso8583Message.class);
//For retrieving 2nd implementation
Iso8583Message iso8583Message=applicationContext.getBean("iso8583-message2", Iso8583Message.class);
String result = iso8583Message.getFundTransfer(bancsxfr);
}
}
In this case, we can configure the bean names coming from the database instead of hard coded values("iso8583-message1","iso8583-message2").
I have Neo4j unmanaged extension. I want some services to be created as singletons and be available via #Context in my resources.
Something like this:
#Path("/example")
public class ExampleResource {
public ExampleResource(#Context CostlyService costlyService) { // <<---
// use it here
}
}
How this can be achieved?
Neo4j has PluginLifecycle interface that give us possibility to hook into Neo4j server lifecycle and provide our own services for injection blog post.
So, we have service. Let's take this one as example:
public interface CostlyService {
}
public class CostlyServiceImpl implements CostlyService {
public CostlyService() {
// a LOT of work done here
}
//...
}
Now we need to make our own PluginLifecycle implementation:
public class ExamplePluginLifecycle implements PluginLifecycle {
#Override
public Collection<Injectable<?>> start(GraphDatabaseService graphDatabaseService,
Configuration config) {
final List<Injectable<?>> injectables = new ArrayList<>();
return injectables;
}
#Override
public void stop() {
}
}
As you see, injectable list is empty for now. We will add our service there soon.
Important: you must register your PluginLifecycle implementation, so it will be available via SPI:
// file: META-INF/services/org.neo4j.server.plugins.PluginLifecycle
my.company.extension.ExamplePluginLifecycle
This will make your PluginLifecycle discoverable by Neo4j server.
Now we need to create actual injectable. Let's write implementation for Injectable interface:
public final class TypedInjectable<T> implements Injectable<T> {
private final T value;
private final Class<T> type;
private TypedInjectable(final T value, final Class<T> type) {
this.value = value;
this.type = type;
}
public static <T> TypedInjectable<T> injectable(final T value, final Class<T> type) {
return new TypedInjectable<>(value, type);
}
#Override
public T getValue() {
return value;
}
#Override
public Class<T> getType() {
return type;
}
}
This will serve as simple container for our service. Usage:
import static my.company.extension.TypedInjectable.injectable;
injectable(new CostlyServiceImpl(), CostlyService.class);
Now we can add our injectable into PluginLifecycle.
#Override
public Collection<Injectable<?>> start(GraphDatabaseService graphDatabaseService,
Configuration config) {
final List<Injectable<?>> injectables = new ArrayList<>();
injectables.add(injectable(new CostlyServiceImpl, CostlyService.class)); // <<---
return injectables;
}
After this change our CostlyService will be available for our resources via #Context:
#Path("/example")
public class ExampleResource {
public ExampleResource(#Context CostlyService costlyService) {
// use it here
}
// ...
}
Tip: keep your PluginLifecycle's in same package or in subpackage with your resources.
I have two classes:
DocumentState and ElectronicDocumentState.
They look like this:
public class DocumentState extends LabeledEnum {
public static final DocumentState CREATED = new DocumentState("created");
// ..... - 15 other statuses
}
ElectronicDocumentState also extends LabeledEnum and has its own statuses, some are common like created, other are unique.
Then I have plenty of methods in code that take DocumentState as a parameter or are returning DocumentState as result. Now they should work also with ElectronicDocumentState.
Also I have plenty places that do:
if (DocumentSate.CREATED.equals(doc.getState()) || DocumentState.DELETED.equals(doc.getState())) {
//do something with document
}
I want to avoid 'if' and avoid creating new methods for ElectronicDocumentState as more state can appear in future.
How would you do that ?
So using the below example, how would you refactor it so it could work with DocumentState and ElectronicDocumentState? I have plenty of such methods that now should also work with ElectronicDocumentState. Someone asks us to mix electronicDocuments with documents in business logic:
private DocumentState getDocumentStateForDetails(Document doc, DocumentState sourceState) {
if (DocumentState.CREATED.equals(doc.getDocumentState())) {
if (sourceState.equals(DocumentState.CREATED)) {
return DocumentState.CREATED;
} else {
return DocumentState.BLOCKED;
}
} else {
return sourceState.getDocumentState();
}
}
If you are worrying about further extension of your state model, I'd suggest you to think about using inheritance instead of if/switch and instanceof by splitting the document class to Value and State, for instance. If you have the same set of available actions for any state of document, just use classical State pattern, otherwise, each State may have its own set of available actions:
public class Document {
public static CreatedDocument<Document> create(String author) {
return new CreatedDocument<>(new Document(author));
}
private String author;
//...
private Document(String author) {
//...
}
}
public class ElectronicDocument extends Document {
public static CreatedElectronicDocument create(String author, String url) {
return new CreatedElectronicDocument(author, url);
}
private String url;
//...
public ElectronicDocument(String author, String url) {
//...
}
//...
}
public interface DocumentState<T extends Document> {
T getDocument();
char getCode(); // might be needed for something like logging?
}
public abstract class AbstractDocumentState<T extends Document> implements DocumentState<T> {
protected final T document;
protected AbstractDocumentState(T document) {
this.document = document;
}
#Override
public T getDocument() {
return document;
}
}
public class CreatedDocument<T extends Document> extends AbstractDocumentState<T> {
public CreatedDocument(T document) {
super(document);
}
#Override
public char getCode() {
return 'C';
}
public DocumentState<T> delete() {
return new DeletedDocument<>(document);
}
}
public class CreatedElectronicDocument extends CreatedDocument<ElectronicDocument> {
public CreatedElectronicDocument(String author, String url) {
super(new ElectronicDocument(author, url));
}
public DownloadElectronicDocument download() {
return new DownloadElectronicDocument(document);
}
}
public class DownloadElectronicDocument extends AbstractDocumentState<ElectronicDocument> {
public DownloadElectronicDocument(ElectronicDocument document) {
super(document);
// DO DOWNLOAD HERE
}
#Override
public char getCode() {
return 'L';
}
public DocumentState<ElectronicDocument> delete() {
return new DeletedDocument<>(document);
}
}
public class DeletedDocument<T extends Document> extends AbstractDocumentState<T> {
public DeletedDocument(T document) {
super(document);
// DO DELETE HERE
}
#Override
public char getCode() {
return 'D';
}
}
Not sure you need getCode() now, when you use inheritance. BTW, switch works faster than a set of if/else if.
If you'd like to stay with your enum classes, why wouldn't to extract common states to a super class?
public class CommonDocumentState extends LabeledEnum {
public static final CommonDocumentState CREATED = new CommonDocumentState ("created");
..... - n other statuses
}
public class DocumentState extends CommonDocumentState {
..... - m other statuses
}
public class ElectronicDocumentState extends CommonDocumentState {
..... - k other statuses
}
That's the only way to have such generic rules like
if (DocumentSate.CREATED.equals(doc.getState()) || DocumentState.DELETED.equals(doc.getState())) {
//do something with document
}
be working for both DocumentState and ElectronicDocumentState.
There are not enough information about your domain to provide a final answer, but I have some suggestions:
it seems that both DocumentState and ElectronicDocumentState inherit from LabeledEnum; if you want to manage both of them in your methods you can make ElectronicDocumentState inherit from DocumentState of it's feasibile merge the two classes. This will allow to pass ElectronicDocumentState or DocumentState in your methods and perhaps solve your second question.
if you want to avoid the if you can build a list of allowed method and check against the list, something like:
L
public class YourClass {
List<DocumentSate> allowedStates=//init here or in constructor
....
public void yourMethod(....) {
if (allowedStates.contains(doc.getState())) {
//do something
}
}
allowedStates may be factored out in separate class if it is a common case. If you find the refactoring feasible, may be you can check if you are dealing with a finite state machine and implement it (with the help of some exisiting libraries).
I have a lot of classes UNO,HAV,MAS,KOS
I want to create a factory pattern.
validator.load("UNO").validate();
I need dynamically load classes into validator class and return an instance.
(dynamically set name of the class and return an instance)
My problem is: how can I return the instance of a class, if I have incompatible types?
I don't know what to write in return type of method.
The main problem in the Validator CLASS.
public SegmentAbstract load(String str) {
AND
return SegmentAbsClass.forName(identify);
Main class
try{
validator.load("UNO").validate();
}catch(Exception e){
System.out.print("No class ");
}
Abstract Class (SegmentAbstract)
public abstract class SegmentAbstract {
public abstract Boolean validate();
}
Class UNO
public class UNA extends SegmentAbstract{
public Boolean validate() {
System.out.print("UNO!!");
return true;
}
}
Class Validator
public class Validator {
public SegmentAbstract load(String str) {
String identify = str.substring(0, 3);
try {
return SegmentAbsClass.forName(identify);
}
catch(Exception e) {
return this;
}
}
}
Try this :
public interface Validator {
boolean validate(Object obj);
}
public final class ValidatorFactory {
private ValidatorFactory(){}
public static Validator load(String type){
try {
Class<?> clazz = Class.forName(type);
if (Arrays.asList(clazz.getInterfaces()).contains(Validator.class)){
return (Validator) clazz.newInstance();
}
throw new IllegalArgumentException("Provided class doesn't implement Validator interface");
} catch (Exception e) {
throw new IllegalArgumentException("Wrong class provided", e);
}
}
}
Maybe this will help???
I will do something like that:
// ISegment.java
public interface ISegment {
Boolean validate();
}
// Uno.java
public class Uno implements ISegment {
public Boolean validate() {
System.out.print("UNO!!");
return true;
}
}
// SegmentFactory.java
public final class SegmentFactory {
public static enum Supported {
UNO("uno", Uno.class), /* ... */, HAV("hav", Hav.class);
private final Class<?> clazz;
private final String name;
private Supported(final String name, final Class<?> clazz) {
this.name = name;
this.clazz = clazz;
}
public Class<?> getClazz() {
return clazz;
}
public static Supported for(final String name) {
for (final Supported s : values()) {
if (s.name.equals(name) {
return s;
}
}
return null; // a default one
}
}
public static ISegment create(final Supported supp) {
if (supp == null) {
return null;
}
return supp.getClazz.newInstance();
}
private SegmentFactory() {
// avoid instantiation
}
}
usage:
final ISegment sa = SegmentFactory.create(SegmentFactory.Supported.for("uno"));
sa.validate();
Not tested!!
Take a look here. Briefly, the idea is to create a map in your factory class (Map<String,String>, key is identifier, value is fully qualified class name), and add supported classes during initialization. Then you use reflection to instantiate an object in your factory method. Also, you can avoid reflection by using Map<String, SegmentAbstract> instead of Map<String,String> and adding public abstract getNewSegment() to your SegmentAbstract class.