RxJavaPlugins, the pattern behind
up vote
0
down vote
favorite
I want to reproduce the "static" injection of RxJava using the RxJavaPlugins and i'am wondring if the design of this class is a well known pattern !?
I have a basic model class for all my events
import lombok.Getter;
public abstract class BasicEvent {
@Getter
private final String id;
@Getter
private final long timestamp;
public BasicEvent() {
this.id = IDGenerator.BY_COUNTER.generate();
this.timestamp = TimePlayer.clock().timestamp();
}
}
The main drawback of the class above is the testability. I cannot change the IDGenerator and the TimePlayer.
I think that having a third party class, designed like RxJavaPlugins could help me changing my metadata generators for tests
UPDATE .
I've followed the RxJavaPlugins solution for keeping model's creation simple, without worrying about the id and the timestamp (i called the two fields metadata), here is solution a found.
public BasicEvent() {
this.id = MetaGenerator.idGenerator().generate();
this.timestamp = MetaGenerator.timePlayer().timestamp();
}
public class MetaGenerator {
public static IDGenerator idGenerator() {
// DGenerator.BY_COUNTER is the default value
return MetaGeneratorPlugins.onIDGenerator(IDGenerator.BY_COUNTER);
}
public static TimePlayer timePlayer() {
return MetaGeneratorPlugins.onTimePlayer(TimePlayer.realtime);
}
}
public class MetaGeneratorPlugins {
private static Function<? super TimePlayer, ? extends TimePlayer> onTimePlayerHandler;
private static Function<? super IDGenerator, ? extends IDGenerator> onIDGeneratorHandler;
public static void setTimePlayerHandler(@Nullable Function<? super TimePlayer, ? extends TimePlayer> handler) {
onTimePlayerHandler = handler;
}
public static void setIDGeneratorHandler(@Nullable Function<? super IDGenerator, ? extends IDGenerator> handler) {
onIDGeneratorHandler = handler;
}
//return the default value or the value returned by the handler
public static TimePlayer onTimePlayer(@Nonnull TimePlayer defaultScheduler) {
if (onTimePlayerHandler == null) {
return defaultScheduler;
}
return apply(onTimePlayerHandler, defaultScheduler);
}
public static IDGenerator onIDGenerator(@Nonnull IDGenerator defaultScheduler) {
if (onIDGeneratorHandler == null) {
return defaultScheduler;
}
return apply(onIDGeneratorHandler, defaultScheduler);
}
private static <T, R> R apply(@Nonnull Function<T, R> f, @Nonnull T t) {
return f.apply(t);
}
}
In my tests now i can change this MetaGenerator's implementation by calling MetaGeneratorPlugins
MetaGeneratorPlugins.setIDGeneratorHandler(IDGenerator.INCREMENTAL);
MetaGeneratorPlugins.setTimePlayerHandler(TimePlayer.simulated);
This is how RxJavaPlugins works, i have been inspired by they solution,
Now the creation of my models are simple and it works for production and tests.
java rx-java2 reactive
add a comment |
up vote
0
down vote
favorite
I want to reproduce the "static" injection of RxJava using the RxJavaPlugins and i'am wondring if the design of this class is a well known pattern !?
I have a basic model class for all my events
import lombok.Getter;
public abstract class BasicEvent {
@Getter
private final String id;
@Getter
private final long timestamp;
public BasicEvent() {
this.id = IDGenerator.BY_COUNTER.generate();
this.timestamp = TimePlayer.clock().timestamp();
}
}
The main drawback of the class above is the testability. I cannot change the IDGenerator and the TimePlayer.
I think that having a third party class, designed like RxJavaPlugins could help me changing my metadata generators for tests
UPDATE .
I've followed the RxJavaPlugins solution for keeping model's creation simple, without worrying about the id and the timestamp (i called the two fields metadata), here is solution a found.
public BasicEvent() {
this.id = MetaGenerator.idGenerator().generate();
this.timestamp = MetaGenerator.timePlayer().timestamp();
}
public class MetaGenerator {
public static IDGenerator idGenerator() {
// DGenerator.BY_COUNTER is the default value
return MetaGeneratorPlugins.onIDGenerator(IDGenerator.BY_COUNTER);
}
public static TimePlayer timePlayer() {
return MetaGeneratorPlugins.onTimePlayer(TimePlayer.realtime);
}
}
public class MetaGeneratorPlugins {
private static Function<? super TimePlayer, ? extends TimePlayer> onTimePlayerHandler;
private static Function<? super IDGenerator, ? extends IDGenerator> onIDGeneratorHandler;
public static void setTimePlayerHandler(@Nullable Function<? super TimePlayer, ? extends TimePlayer> handler) {
onTimePlayerHandler = handler;
}
public static void setIDGeneratorHandler(@Nullable Function<? super IDGenerator, ? extends IDGenerator> handler) {
onIDGeneratorHandler = handler;
}
//return the default value or the value returned by the handler
public static TimePlayer onTimePlayer(@Nonnull TimePlayer defaultScheduler) {
if (onTimePlayerHandler == null) {
return defaultScheduler;
}
return apply(onTimePlayerHandler, defaultScheduler);
}
public static IDGenerator onIDGenerator(@Nonnull IDGenerator defaultScheduler) {
if (onIDGeneratorHandler == null) {
return defaultScheduler;
}
return apply(onIDGeneratorHandler, defaultScheduler);
}
private static <T, R> R apply(@Nonnull Function<T, R> f, @Nonnull T t) {
return f.apply(t);
}
}
In my tests now i can change this MetaGenerator's implementation by calling MetaGeneratorPlugins
MetaGeneratorPlugins.setIDGeneratorHandler(IDGenerator.INCREMENTAL);
MetaGeneratorPlugins.setTimePlayerHandler(TimePlayer.simulated);
This is how RxJavaPlugins works, i have been inspired by they solution,
Now the creation of my models are simple and it works for production and tests.
java rx-java2 reactive
add a comment |
up vote
0
down vote
favorite
up vote
0
down vote
favorite
I want to reproduce the "static" injection of RxJava using the RxJavaPlugins and i'am wondring if the design of this class is a well known pattern !?
I have a basic model class for all my events
import lombok.Getter;
public abstract class BasicEvent {
@Getter
private final String id;
@Getter
private final long timestamp;
public BasicEvent() {
this.id = IDGenerator.BY_COUNTER.generate();
this.timestamp = TimePlayer.clock().timestamp();
}
}
The main drawback of the class above is the testability. I cannot change the IDGenerator and the TimePlayer.
I think that having a third party class, designed like RxJavaPlugins could help me changing my metadata generators for tests
UPDATE .
I've followed the RxJavaPlugins solution for keeping model's creation simple, without worrying about the id and the timestamp (i called the two fields metadata), here is solution a found.
public BasicEvent() {
this.id = MetaGenerator.idGenerator().generate();
this.timestamp = MetaGenerator.timePlayer().timestamp();
}
public class MetaGenerator {
public static IDGenerator idGenerator() {
// DGenerator.BY_COUNTER is the default value
return MetaGeneratorPlugins.onIDGenerator(IDGenerator.BY_COUNTER);
}
public static TimePlayer timePlayer() {
return MetaGeneratorPlugins.onTimePlayer(TimePlayer.realtime);
}
}
public class MetaGeneratorPlugins {
private static Function<? super TimePlayer, ? extends TimePlayer> onTimePlayerHandler;
private static Function<? super IDGenerator, ? extends IDGenerator> onIDGeneratorHandler;
public static void setTimePlayerHandler(@Nullable Function<? super TimePlayer, ? extends TimePlayer> handler) {
onTimePlayerHandler = handler;
}
public static void setIDGeneratorHandler(@Nullable Function<? super IDGenerator, ? extends IDGenerator> handler) {
onIDGeneratorHandler = handler;
}
//return the default value or the value returned by the handler
public static TimePlayer onTimePlayer(@Nonnull TimePlayer defaultScheduler) {
if (onTimePlayerHandler == null) {
return defaultScheduler;
}
return apply(onTimePlayerHandler, defaultScheduler);
}
public static IDGenerator onIDGenerator(@Nonnull IDGenerator defaultScheduler) {
if (onIDGeneratorHandler == null) {
return defaultScheduler;
}
return apply(onIDGeneratorHandler, defaultScheduler);
}
private static <T, R> R apply(@Nonnull Function<T, R> f, @Nonnull T t) {
return f.apply(t);
}
}
In my tests now i can change this MetaGenerator's implementation by calling MetaGeneratorPlugins
MetaGeneratorPlugins.setIDGeneratorHandler(IDGenerator.INCREMENTAL);
MetaGeneratorPlugins.setTimePlayerHandler(TimePlayer.simulated);
This is how RxJavaPlugins works, i have been inspired by they solution,
Now the creation of my models are simple and it works for production and tests.
java rx-java2 reactive
I want to reproduce the "static" injection of RxJava using the RxJavaPlugins and i'am wondring if the design of this class is a well known pattern !?
I have a basic model class for all my events
import lombok.Getter;
public abstract class BasicEvent {
@Getter
private final String id;
@Getter
private final long timestamp;
public BasicEvent() {
this.id = IDGenerator.BY_COUNTER.generate();
this.timestamp = TimePlayer.clock().timestamp();
}
}
The main drawback of the class above is the testability. I cannot change the IDGenerator and the TimePlayer.
I think that having a third party class, designed like RxJavaPlugins could help me changing my metadata generators for tests
UPDATE .
I've followed the RxJavaPlugins solution for keeping model's creation simple, without worrying about the id and the timestamp (i called the two fields metadata), here is solution a found.
public BasicEvent() {
this.id = MetaGenerator.idGenerator().generate();
this.timestamp = MetaGenerator.timePlayer().timestamp();
}
public class MetaGenerator {
public static IDGenerator idGenerator() {
// DGenerator.BY_COUNTER is the default value
return MetaGeneratorPlugins.onIDGenerator(IDGenerator.BY_COUNTER);
}
public static TimePlayer timePlayer() {
return MetaGeneratorPlugins.onTimePlayer(TimePlayer.realtime);
}
}
public class MetaGeneratorPlugins {
private static Function<? super TimePlayer, ? extends TimePlayer> onTimePlayerHandler;
private static Function<? super IDGenerator, ? extends IDGenerator> onIDGeneratorHandler;
public static void setTimePlayerHandler(@Nullable Function<? super TimePlayer, ? extends TimePlayer> handler) {
onTimePlayerHandler = handler;
}
public static void setIDGeneratorHandler(@Nullable Function<? super IDGenerator, ? extends IDGenerator> handler) {
onIDGeneratorHandler = handler;
}
//return the default value or the value returned by the handler
public static TimePlayer onTimePlayer(@Nonnull TimePlayer defaultScheduler) {
if (onTimePlayerHandler == null) {
return defaultScheduler;
}
return apply(onTimePlayerHandler, defaultScheduler);
}
public static IDGenerator onIDGenerator(@Nonnull IDGenerator defaultScheduler) {
if (onIDGeneratorHandler == null) {
return defaultScheduler;
}
return apply(onIDGeneratorHandler, defaultScheduler);
}
private static <T, R> R apply(@Nonnull Function<T, R> f, @Nonnull T t) {
return f.apply(t);
}
}
In my tests now i can change this MetaGenerator's implementation by calling MetaGeneratorPlugins
MetaGeneratorPlugins.setIDGeneratorHandler(IDGenerator.INCREMENTAL);
MetaGeneratorPlugins.setTimePlayerHandler(TimePlayer.simulated);
This is how RxJavaPlugins works, i have been inspired by they solution,
Now the creation of my models are simple and it works for production and tests.
java rx-java2 reactive
java rx-java2 reactive
edited Nov 10 at 11:21
asked Nov 9 at 14:29
Elma Cherb
11
11
add a comment |
add a comment |
1 Answer
1
active
oldest
votes
up vote
1
down vote
Change the design of BasicEvent so that the id and timestamp are bound in a more testable fashion.
Introduce a "stamper" interface:
public interface Stamper {
String generateId();
long generateTimestamp();
}
The "default" implementation would look like:
public RealTimeStamper implements Stamper {
@Override public String generateId() {
return IDGenerator.BY_COUNTER.generate();
}
@Override public long generateTimestamp() {
return TimePlayer.clock().timestamp();
}
}
Provide a testable implementation of Stamper. Then bind the appropriate implementation using whatever dependency injection process you use.
public abstract class BasicEvent {
static Stamper stamper;
...
public BasicEvent() {
this.id = stamper.generateId();
this.timestamp = stamper.generateTimestamp();
}
}
The stamper field can be injected either manually or using a dependency injection framework.
Sorry i can't show you my final code because of the auto ban, i'll try to put it on github for more explanation
– Elma Cherb
Nov 10 at 11:18
i've updated my poste above. My response is after the UPDATE line
– Elma Cherb
Nov 10 at 11:22
Your solution looks to be a comprehensive answer to your original question. It uses dependency injection to provide the values that you need when you need them. As such, there is nothing I can add to it. Or remove.
– Bob Dalgleish
Nov 13 at 17:43
add a comment |
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
up vote
1
down vote
Change the design of BasicEvent so that the id and timestamp are bound in a more testable fashion.
Introduce a "stamper" interface:
public interface Stamper {
String generateId();
long generateTimestamp();
}
The "default" implementation would look like:
public RealTimeStamper implements Stamper {
@Override public String generateId() {
return IDGenerator.BY_COUNTER.generate();
}
@Override public long generateTimestamp() {
return TimePlayer.clock().timestamp();
}
}
Provide a testable implementation of Stamper. Then bind the appropriate implementation using whatever dependency injection process you use.
public abstract class BasicEvent {
static Stamper stamper;
...
public BasicEvent() {
this.id = stamper.generateId();
this.timestamp = stamper.generateTimestamp();
}
}
The stamper field can be injected either manually or using a dependency injection framework.
Sorry i can't show you my final code because of the auto ban, i'll try to put it on github for more explanation
– Elma Cherb
Nov 10 at 11:18
i've updated my poste above. My response is after the UPDATE line
– Elma Cherb
Nov 10 at 11:22
Your solution looks to be a comprehensive answer to your original question. It uses dependency injection to provide the values that you need when you need them. As such, there is nothing I can add to it. Or remove.
– Bob Dalgleish
Nov 13 at 17:43
add a comment |
up vote
1
down vote
Change the design of BasicEvent so that the id and timestamp are bound in a more testable fashion.
Introduce a "stamper" interface:
public interface Stamper {
String generateId();
long generateTimestamp();
}
The "default" implementation would look like:
public RealTimeStamper implements Stamper {
@Override public String generateId() {
return IDGenerator.BY_COUNTER.generate();
}
@Override public long generateTimestamp() {
return TimePlayer.clock().timestamp();
}
}
Provide a testable implementation of Stamper. Then bind the appropriate implementation using whatever dependency injection process you use.
public abstract class BasicEvent {
static Stamper stamper;
...
public BasicEvent() {
this.id = stamper.generateId();
this.timestamp = stamper.generateTimestamp();
}
}
The stamper field can be injected either manually or using a dependency injection framework.
Sorry i can't show you my final code because of the auto ban, i'll try to put it on github for more explanation
– Elma Cherb
Nov 10 at 11:18
i've updated my poste above. My response is after the UPDATE line
– Elma Cherb
Nov 10 at 11:22
Your solution looks to be a comprehensive answer to your original question. It uses dependency injection to provide the values that you need when you need them. As such, there is nothing I can add to it. Or remove.
– Bob Dalgleish
Nov 13 at 17:43
add a comment |
up vote
1
down vote
up vote
1
down vote
Change the design of BasicEvent so that the id and timestamp are bound in a more testable fashion.
Introduce a "stamper" interface:
public interface Stamper {
String generateId();
long generateTimestamp();
}
The "default" implementation would look like:
public RealTimeStamper implements Stamper {
@Override public String generateId() {
return IDGenerator.BY_COUNTER.generate();
}
@Override public long generateTimestamp() {
return TimePlayer.clock().timestamp();
}
}
Provide a testable implementation of Stamper. Then bind the appropriate implementation using whatever dependency injection process you use.
public abstract class BasicEvent {
static Stamper stamper;
...
public BasicEvent() {
this.id = stamper.generateId();
this.timestamp = stamper.generateTimestamp();
}
}
The stamper field can be injected either manually or using a dependency injection framework.
Change the design of BasicEvent so that the id and timestamp are bound in a more testable fashion.
Introduce a "stamper" interface:
public interface Stamper {
String generateId();
long generateTimestamp();
}
The "default" implementation would look like:
public RealTimeStamper implements Stamper {
@Override public String generateId() {
return IDGenerator.BY_COUNTER.generate();
}
@Override public long generateTimestamp() {
return TimePlayer.clock().timestamp();
}
}
Provide a testable implementation of Stamper. Then bind the appropriate implementation using whatever dependency injection process you use.
public abstract class BasicEvent {
static Stamper stamper;
...
public BasicEvent() {
this.id = stamper.generateId();
this.timestamp = stamper.generateTimestamp();
}
}
The stamper field can be injected either manually or using a dependency injection framework.
answered Nov 9 at 17:20
Bob Dalgleish
5,5311933
5,5311933
Sorry i can't show you my final code because of the auto ban, i'll try to put it on github for more explanation
– Elma Cherb
Nov 10 at 11:18
i've updated my poste above. My response is after the UPDATE line
– Elma Cherb
Nov 10 at 11:22
Your solution looks to be a comprehensive answer to your original question. It uses dependency injection to provide the values that you need when you need them. As such, there is nothing I can add to it. Or remove.
– Bob Dalgleish
Nov 13 at 17:43
add a comment |
Sorry i can't show you my final code because of the auto ban, i'll try to put it on github for more explanation
– Elma Cherb
Nov 10 at 11:18
i've updated my poste above. My response is after the UPDATE line
– Elma Cherb
Nov 10 at 11:22
Your solution looks to be a comprehensive answer to your original question. It uses dependency injection to provide the values that you need when you need them. As such, there is nothing I can add to it. Or remove.
– Bob Dalgleish
Nov 13 at 17:43
Sorry i can't show you my final code because of the auto ban, i'll try to put it on github for more explanation
– Elma Cherb
Nov 10 at 11:18
Sorry i can't show you my final code because of the auto ban, i'll try to put it on github for more explanation
– Elma Cherb
Nov 10 at 11:18
i've updated my poste above. My response is after the UPDATE line
– Elma Cherb
Nov 10 at 11:22
i've updated my poste above. My response is after the UPDATE line
– Elma Cherb
Nov 10 at 11:22
Your solution looks to be a comprehensive answer to your original question. It uses dependency injection to provide the values that you need when you need them. As such, there is nothing I can add to it. Or remove.
– Bob Dalgleish
Nov 13 at 17:43
Your solution looks to be a comprehensive answer to your original question. It uses dependency injection to provide the values that you need when you need them. As such, there is nothing I can add to it. Or remove.
– Bob Dalgleish
Nov 13 at 17:43
add a comment |
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53227635%2frxjavaplugins-the-pattern-behind%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown