I want to check when a mock is called with a realtimeUpdate which currentTime field equals some LocalDateTime:
I want to run such code with a custom matcher:
verify(mockServerApi).sendUpdate(new TimeMatcher().isTimeEqual(update, localDateTime2));
but I have a compilation error when I try to run with this custom matcher.
How can I fix this?
public class TimeMatcher {
public Matcher<RealtimeUpdate> isTimeEqual(RealtimeUpdate realtimeUpdate, final LocalDateTime localDateTime) {
return new BaseMatcher<RealtimeUpdate>() {
#Override
public boolean matches(final Object item) {
final RealtimeUpdate realtimeUpdate = (RealtimeUpdate) item;
return realtimeUpdate.currentTime.equalTo(localDateTime);
}
this is the method signature
void sendRealTimeUpdate(RealtimeUpdate realtimeUpdate);
and this is the compilation error:
Here is how you could proceed
The class TimeMatcher, you need only the LocalDateTime
public class TimeMatcher {
public static Matcher<RealtimeUpdate> isTimeEqual(final LocalDateTime localDateTime) {
return new BaseMatcher<RealtimeUpdate>() {
#Override
public void describeTo(final Description description) {
description.appendText("Date doesn't match with "+ localDateTime);
}
#Override
public boolean matches(final Object item) {
final RealtimeUpdate realtimeUpdate = (RealtimeUpdate) item;
return realtimeUpdate.currentTime.isEqual(localDateTime);
}
};
}
}
The test:
Mockito.verify(mockRoutingServerApi).sendRealTimeUpdate(
new ThreadSafeMockingProgress().getArgumentMatcherStorage()
.reportMatcher(TimeMatcher.isTimeEqual(localDateTime2))
.returnFor(RealtimeUpdate.class));
You need to use returnFor to provide the argument type which is RealtimeUpdate as expected by sendRealTimeUpdate
This is equivalent to:
Mockito.verify(mockRoutingServerApi).sendRealTimeUpdate(
Matchers.argThat(TimeMatcher.isTimeEqual(localDateTime2))
);
Related
Small question regarding the diamond operator and design pattern strategy for Java, please.
I would like to implement a very specific requirement:
there are some objects to store (in my example called MyThingToStore)
and the requirement is to store them with different kinds of data structures, for comparison.
Therefore, I went to try with a strategy pattern, where each of the strategies is a different way to store, I think this pattern is quite lovely.
The code is as follows:
public class MyThingToStore {
private final String name;
public MyThingToStore(String name) {
this.name = name;
}
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
MyThingToStore that = (MyThingToStore) o;
return Objects.equals(name, that.name);
}
#Override
public int hashCode() {
return Objects.hash(name);
}
#Override
public String toString() {
return "MyThingToStore{" +
"name='" + name + '\'' +
'}';
}
}
public class MyStorage {
private final StorageStrategy storageStrategy;
public MyStorage(StorageStrategy storageStrategy) {
this.storageStrategy = storageStrategy;
}
public void addToStore(MyThingToStore myThingToStore) {
storageStrategy.addToStore(myThingToStore);
}
public int getSize() {
return storageStrategy.getSize();
}
}
public interface StorageStrategy {
void addToStore(MyThingToStore myThingToStore);
int getSize();
}
public class StorageUsingArrayListStrategy implements StorageStrategy {
private final List<MyThingToStore> storeUsingArrayList = new ArrayList<>();
#Override
public void addToStore(MyThingToStore myThingToStore) {
storeUsingArrayList.add(myThingToStore);
}
#Override
public int getSize() {
return storeUsingArrayList.size();
}
}
public class StorageUsingHashSetStrategy implements StorageStrategy{
private final Set<MyThingToStore> storeUsingHashSet = new HashSet<>();
#Override
public void addToStore(MyThingToStore myThingToStore) {
storeUsingHashSet.add(myThingToStore);
}
#Override
public int getSize() {
return storeUsingHashSet.size();
}
}
public class Main {
public static void main(String[] args) {
final StorageStrategy storageStrategy = new StorageUsingArrayListStrategy();
final MyStorage myStorage = new MyStorage(storageStrategy);
myStorage.addToStore(new MyThingToStore("firstItem"));
myStorage.addToStore(new MyThingToStore("duplicatedSecondItem"));
myStorage.addToStore(new MyThingToStore("duplicatedSecondItem"));
System.out.println(myStorage.getSize()); //changing strategy will return a different size, working!
}
}
And this is working fine, very happy, especially tackled the requirement "easy to change the data structure to do the actual store".
(By the way, side question, if there is an even better way to do this, please let me know!)
Now, looking online at different implementations of strategy patterns, I see this diamond operator which I am having a hard time understanding:
MyThingToStore stays the same.
public class MyStorage {
private final StorageStrategy<MyThingToStore> storageStrategy; //note the diamond here
public MyStorage(StorageStrategy<MyThingToStore> storageStrategy) {
this.storageStrategy = storageStrategy;
}
public void addToStore(MyThingToStore myThingToStore) {
storageStrategy.addToStore(myThingToStore);
}
public int getSize() {
return storageStrategy.getSize();
}
#Override
public String toString() {
return "MyStorage{" +
"storageStrategy=" + storageStrategy +
'}';
}
}
public interface StorageStrategy<MyThingToStore> {
//note the diamond, and it will be colored differently in IDEs
void addToStore(MyThingToStore myThingToStore);
int getSize();
}
public class StorageUsingArrayListStrategy implements StorageStrategy<MyThingToStore> {
private final List<MyThingToStore> storeUsingArrayList = new ArrayList<>();
#Override
public void addToStore(MyThingToStore myThingToStore) {
storeUsingArrayList.add(myThingToStore);
}
#Override
public int getSize() {
return storeUsingArrayList.size();
}
}
public class StorageUsingHashSetStrategy implements StorageStrategy<MyThingToStore> {
private final Set<MyThingToStore> storeUsingHashSet = new HashSet<>();
#Override
public void addToStore(MyThingToStore myThingToStore) {
storeUsingHashSet.add(myThingToStore);
}
#Override
public int getSize() {
return storeUsingHashSet.size();
}
}
public class Main {
public static void main(String[] args) {
final StorageStrategy<MyThingToStore> storageStrategy = new StorageUsingArrayListStrategy();
final MyStorage myStorage = new MyStorage(storageStrategy);
myStorage.addToStore(new MyThingToStore("firstItem"));
myStorage.addToStore(new MyThingToStore("duplicatedSecondItem"));
myStorage.addToStore(new MyThingToStore("duplicatedSecondItem"));
System.out.println(myStorage.getSize()); //changing strategy will return a different size, working!
}
}
And both versions will yield the same good result, also be able to answer requirements.
My question is: what are the differences between the version without a diamond operator, and the version with the diamond operator, please?
Which of the two ways are "better" and why?
While this question might appear to be "too vague", I believe there is a reason for a better choice.
I think the confusion comes from how you named type parameter for StorageStrategy in your 2nd example.
Let's name it T for type instead. T in this case is just a placeholder to express what type of objects your StorageStrategy can work with.
public interface StorageStrategy<T> {
void addToStore(T myThingToStore);
int getSize();
}
E.g.
StorageStrategy<MyThingToStore> strategy1 = // Initialization
StorageStrategy<String> strategy2 = // Initialization
strategy1.addToStore(new MyThingToStore("Apple"));
// This works fine, because strategy2 accepts "String" instead of "MyThingToStore"
strategy2.addToStore("Apple");
// Last line doesn't work, because strategy1 can only handle objects of type "MyThingToStore"
strategy1.addToStore("Apple");
To make it work properly, you need to change your different StorageStrategy implementations to also include the type parameter.
public class StorageUsingHashSetStrategy<T> implements StorageStrategy<T> {
private final Set<T> storeUsingHashSet = new HashSet<>();
#Override
public void addToStore(T myThingToStore) {
storeUsingHashSet.add(myThingToStore);
}
#Override
public int getSize() {
return storeUsingHashSet.size();
}
}
And lastly you also want to have a type paremeter for MyStorage
public class MyStorage<T> {
private final StorageStrategy<T> storageStrategy;
public MyStorage(StorageStrategy<T> storageStrategy) {
this.storageStrategy = storageStrategy;
}
public void addToStore(T myThingToStore) {
storageStrategy.addToStore(myThingToStore);
}
public int getSize() {
return storageStrategy.getSize();
}
}
Now you can create a MyStorage and can use it to store essentially any object into it and not just MyThingToStore. Whether that is something you want or not is up to you.
In the second code sample in the declaration of the interface StorageStrategy<MyThingToStore>, MyThingToStore is a Type Variable.
I.e. it's not the actual type, only a placeholder for a type, like T. The common convention is to use single-letter generic type variables (T, U, R, etc.), otherwise it might look confusing like in this case.
Note that in the class declarations, like:
public class StorageUsingArrayListStrategy
implements StorageStrategy<MyThingToStore>
MyThingToStore is no longer a type variable, but the name of the class MyThingToStore because in this case parameterized interface is implemented by a non-parameterized class (i.e. the actual type known to the compile is expected to be provided).
I'm implementing a web service respecting version 4 of the OData standard in Java language with the framework Olingo. I need to customize the response of $filter. I've implemented a Visitor as documented in the quick start. I need to implement an integration Test to try a different kind of grammar and to prevent regression bug in case of future maintenance.
For the V2, I found the following tutorial and the following code :
#Test
public void printExpressionWithProperty() throws Exception {
//Use a mocked edmProvider for this tutorial
TestEdmProvider provider = new TestEdmProvider();
Edm edm = RuntimeDelegate.createEdm(provider);
EdmEntityType entityType = edm.getEntityType(TestEdmProvider.NAMESPACE_1, TestEdmProvider.ENTITY_TYPE_1_1.getName());
String rawExpression = "EmployeeId eq '1'";
FilterExpression expression = UriParser.parseFilter (null, entityType, rawExpression);
String whereClause = (String) expression.accept(new JdbcSimpleStringVisitor());
System.out.println("Raw: " + rawExpression + " ------> Whereclause: " + whereClause);
System.out.println();
}
Unfortunately, UriParser.parseFilter doesn't exist in the v4.
I tried this :
public class MyVisitorTest {
private final FullQualifiedName NAME1 = new FullQualifiedName("testNamespace1", "myfield");
private final OData odata = OData.newInstance();
public EdmEntityType createEntityType(final FullQualifiedName fqn) {
if (NAME1.equals(fqn)) {
EdmEntityType entityType = mock(EdmEntityType.class);
when(entityType.getNamespace()).thenReturn(fqn.getNamespace());
when(entityType.getName()).thenReturn(fqn.getName());
return entityType;
}
return null;
}
private Expression parseExpression(final String expressionString)
throws UriParserException, UriValidationException {
UriTokenizer tokenizer = new UriTokenizer(expressionString);
EdmEntityType entityType = createEntityType(NAME1);
Edm edm = mock(Edm.class);
when(edm.getEntityType(NAME1)).thenReturn(entityType);
final Expression expression = new ExpressionParser(edm, odata).parse(tokenizer, null, null, null);
assertNotNull(expression);
assertTrue(tokenizer.next(UriTokenizer.TokenKind.EOF));
return expression;
}
#Test
public void simpleTest() throws UriParserException, UriValidationException, ODataApplicationException, ExpressionVisitException {
String exp = "myfield gt 2019-01-01T00:00:00Z";
Expression e = parseExpression(exp);
MyVisitor myVisitor = new MyVisitor();
String result = (String) e.accept(startEndMeasureVisitor);
assertEquals(result.toString(), "MyResult");
}
}
And it doesn't work, it sends me the following message :
Property paths must follow a structured type.
So I'm looking for any ideas to make my unit test to work or if you've got working example to share...
When it comes to unit tests, I'd focus on testing every filter method separately. Like if visitBinaryOperator returns an expected value based on the input and so on.
I'm not an expert in naming things, but I'd call your test an integration test. Here, I'd focus on testing FilterOption prepared inside the test. In your original app, Apache Olingo will create this FilterOption and this part is (should be) tested in Olingo.
When I worked with Apache Olingo I was frequently referring to its repository, especially to server-test and server-tecsvc. To verify how things are tested in Olingo itself.
I'd recommend to take a look at FilterValidator as it may be something useful for your integration test.
Here we go, thanks to tracing function of mockup (very usefull with legacy code), I've got the new version of parseExpression method that answer my question.
class A implements EdmStructuredType, EdmPrimitiveType {
#Override
public boolean isCompatible(EdmPrimitiveType edmPrimitiveType) {
return false;
}
#Override
public Class<?> getDefaultType() {
return null;
}
#Override
public boolean validate(String s, Boolean aBoolean, Integer integer, Integer integer1, Integer integer2, Boolean aBoolean1) {
return false;
}
#Override
public <T> T valueOfString(String s, Boolean aBoolean, Integer integer, Integer integer1, Integer integer2, Boolean aBoolean1, Class<T> aClass) throws EdmPrimitiveTypeException {
return null;
}
#Override
public String valueToString(Object o, Boolean aBoolean, Integer integer, Integer integer1, Integer integer2, Boolean aBoolean1) throws EdmPrimitiveTypeException {
return null;
}
#Override
public String toUriLiteral(String s) {
return null;
}
#Override
public String fromUriLiteral(String s) throws EdmPrimitiveTypeException {
return null;
}
#Override
public EdmElement getProperty(String s) {
return null;
}
#Override
public List<String> getPropertyNames() {
return null;
}
#Override
public EdmProperty getStructuralProperty(String s) {
return null;
}
#Override
public EdmNavigationProperty getNavigationProperty(String s) {
return null;
}
#Override
public List<String> getNavigationPropertyNames() {
return null;
}
#Override
public EdmStructuredType getBaseType() {
return null;
}
#Override
public boolean compatibleTo(EdmType edmType) {
return false;
}
#Override
public boolean isOpenType() {
return false;
}
#Override
public boolean isAbstract() {
return false;
}
#Override
public EdmAnnotation getAnnotation(EdmTerm edmTerm, String s) {
return null;
}
#Override
public List<EdmAnnotation> getAnnotations() {
return null;
}
#Override
public FullQualifiedName getFullQualifiedName() {
return null;
}
#Override
public String getNamespace() {
return null;
}
#Override
public EdmTypeKind getKind() {
return null;
}
#Override
public String getName() {
return null;
}
}
private Expression parseExpression(final String expressionString)
throws UriParserException, UriValidationException {
UriTokenizer tokenizer = new UriTokenizer(expressionString);
Edm edm = mock(A.class, withSettings().defaultAnswer(RETURNS_SMART_NULLS));
EdmProperty employeeIdTypeEdmElement = mock(EdmProperty.class, RETURNS_SMART_NULLS);
when(edmType.getProperty("EmployeeId")).thenReturn(measureTypeEdmElement);
when(edmType.getKind()).thenReturn(EdmTypeKind.PRIMITIVE);
when(edmType.isCompatible(new EdmDate())).thenReturn(true);
when(employeeIdTypeEdmElement.getName()).thenReturn("EmployeeId");
when(employeeIdTypeEdmElement.getType()).thenReturn(edmType);
when(employeeIdTypeEdmElement.isCollection()).thenReturn(false);
final Expression expression = new ExpressionParser(edm, odata).parse(tokenizer, edmType, null, null);
assertNotNull(expression);
assertTrue(tokenizer.next(UriTokenizer.TokenKind.EOF));
return expression;
}
In case it helps someone, maybee it can be optimized, fill free to propose.
So, after this question where I basically exploits reflection for passing primitive references to modify the primitive itself, like:
_begin("Another Window", ::showAnotherWindow)
I was looking for something to make something similar possible also from java, where at the moment I am using plains primitive arrays:
private boolean[] showAnotherWindow = {false};
imgui.begin("Another Window", showAnotherWindow);
#hotkey suggested me the possibility to create a class implementing the KMutableProperty0 interface and that automatically gets and sets the corresponding variable
Example:
KMutableProperty0<Boolean> prop =
PropUtils.javaProp(this, t -> t.showAnotherWindow, (t, r) -> { t.showAnotherWindow = r; });
_begin("Another Window", prop);
So, I wanted to give it a try and implemented the following in java.
Getter:
#FunctionalInterface
public interface Getter<T> {
T get();
}
Setter:
#FunctionalInterface
public interface Setter<T> {
void set(T type);
}
And then the class itself (I just wrote the constructor, all the methods are those requested by the interface and automatically implemented by the IDE) :
public class JavaProp <T> implements KMutableProperty0<T> {
private imgui.Getter<T> getter;
private imgui.Setter<T> setter;
public JavaProp(imgui.Getter<T> getter, imgui.Setter<T> setter) {
this.getter = getter;
this.setter = setter;
}
#Override
public void set(T t) {
setter.set(t);
}
#NotNull
#Override
public Setter<T> getSetter() {
return null;
}
#Override
public T get() {
return getter.get();
}
#Nullable
#Override
public Object getDelegate() {
return null;
}
#NotNull
#Override
public Getter<T> getGetter() {
return null;
}
#Override
public T invoke() {
return null;
}
#Override
public boolean isLateinit() {
return false;
}
#Override
public boolean isConst() {
return false;
}
#NotNull
#Override
public String getName() {
return null;
}
#NotNull
#Override
public List<KParameter> getParameters() {
return null;
}
#NotNull
#Override
public KType getReturnType() {
return null;
}
#NotNull
#Override
public List<KTypeParameter> getTypeParameters() {
return null;
}
#Override
public T call(Object... objects) {
return null;
}
#Override
public T callBy(Map<KParameter, ?> map) {
return null;
}
#Nullable
#Override
public KVisibility getVisibility() {
return null;
}
#Override
public boolean isFinal() {
return false;
}
#Override
public boolean isOpen() {
return false;
}
#Override
public boolean isAbstract() {
return false;
}
#NotNull
#Override
public List<Annotation> getAnnotations() {
return null;
}
}
But whenever I try to run that, I get the following:
Error:(45, 12) java: reference to Getter is ambiguous
both interface kotlin.reflect.KProperty0.Getter in kotlin.reflect.KProperty0 and interface kotlin.reflect.KProperty.Getter in kotlin.reflect.KProperty match
The problematic function is this one:
#NotNull
#Override
public Getter<T> getGetter() {
return null;
}
And the relevant file is kotlin.reflect.KProperty.tk, you can find it here
Any idea how could I solve it?
Just specify which interface you mean:
public KProperty0.Getter<T> getGetter()
But I would prefer to implement the class in Kotlin and only consume it from Java.
I am implementing a rule-engine in Java. My rule-engine predefines a list of independent rules and rule sets. A rule here is simply a piece of logic. And a rule set combines these simple rules into an ordered set.
I am a decent java developer but not a Guru. My colleague suggested me two designs for this purpose. I am not satisfied with both the designs, hence this question.
Example of a Rule in my project:
Say the inputs are locations in USA for e.g., Santa Barbara, CA, USA or OH, US which is usually in some well defined format with the city, state and country fields. Then I can have some rules as follows:
RULE 1: City not null
RULE 2: State not null
RULE 3: Country equals US or USA
RULE 4: State length equals 2
Example of a RuleSet in my project:
RULESET: Valid location
This ruleset is an ordered set of the above defined rules.
The two design templates I have implemented are as follows:
Design 1: Using Enum with Anonymous Inner classes
Rule.java
public interface Rule {
public Object apply(Object object);
}
NlpRule.java
public enum NlpRule {
CITY_NOT_NULL(new Rule() {
#Override
public Object apply(Object object) {
String location = (String) object;
String city = location.split(",")[0];
if (city != null) {
return true;
}
return false;
}
}),
STATE_NOT_NULL(new Rule() {
#Override
public Object apply(Object object) {
String location = (String) object;
String state = location.split(",")[1];
if (state != null) {
return true;
}
return false;
}
}),
COUNTRY_US(new Rule() {
#Override
public Object apply(Object object) {
String location = (String) object;
String country = location.split(",")[2];
if (country.equals("US") || country.equals("USA")) {
return true;
}
return false;
}
}),
STATE_ABBREVIATED(new Rule() {
#Override
public Object apply(Object object) {
String location = (String) object;
String state = location.split(",")[1];
if (state.length() == 2) {
return true;
}
return false;
}
});
private Rule rule;
NlpRule(Rule rule) {
this.rule = rule;
}
public Object apply(Object object) {
return rule.apply(object);
}
}
RuleSet.java
public class RuleSet {
private List<NlpRule> rules;
public RuleSet() {
rules = new ArrayList<NlpRule>();
}
public RuleSet(List<NlpRule> rules) {
this.rules = rules;
}
public void add(NlpRule rule) {
rules.add(rule);
}
public boolean apply(Object object) throws Exception {
boolean state = false;
for (NlpRule rule : rules) {
state = (boolean) rule.apply(object);
}
return state;
}
}
RuleSets.java
public class RuleSets {
private RuleSets() {
}
public static RuleSet isValidLocation() {
RuleSet ruleSet = new RuleSet();
ruleSet.add(NlpRule.CITY_NOT_NULL);
ruleSet.add(NlpRule.STATE_NOT_NULL);
ruleSet.add(NlpRule.COUNTRY_US);
ruleSet.add(NlpRule.STATE_ABBREVIATED);
return ruleSet;
}
}
Main.java
public class Main {
public static void main(String... args) {
String location = "Santa Barbara,CA,USA";
RuleSet ruleSet = RuleSets.isValidLocation();
try {
boolean isValid = (boolean) ruleSet.apply(location);
System.out.println(isValid);
} catch (Exception e) {
e.getMessage();
}
}
}
Design 2: Using Abstract Class
NlpRule.java
public abstract class NlpRule {
public abstract Object apply(Object object);
public final static NlpRule CITY_NOT_NULL = new NlpRule() {
public Object apply(Object object) {
String location = (String) object;
String city = location.split(",")[0];
if (city != null) {
return true;
}
return false;
}
};
public final static NlpRule STATE_NOT_NULL = new NlpRule() {
public Object apply(Object object) {
String location = (String) object;
String city = location.split(",")[0];
if (city != null) {
return true;
}
return false;
}
};
public final static NlpRule COUNTRY_US = new NlpRule() {
public Object apply(Object object) {
String location = (String) object;
String country = location.split(",")[2];
if (country.equals("US") || country.equals("USA")) {
return true;
}
return false;
}
};
public final static NlpRule STATE_ABBREVIATED = new NlpRule() {
public Object apply(Object object) {
String location = (String) object;
String state = location.split(",")[1];
if (state.length() == 2) {
return true;
}
return false;
}
};
}
RuleSet.java
public class RuleSet {
private List<NlpRule> rules;
public RuleSet() {
rules = new ArrayList<NlpRule>();
}
public RuleSet(List<NlpRule> rules) {
this.rules = rules;
}
public void add(NlpRule rule) {
rules.add(rule);
}
public boolean apply(Object object) throws Exception {
boolean state = false;
for (NlpRule rule : rules) {
state = (boolean) rule.apply(object);
}
return state;
}
}
RuleSets.java
import com.hgdata.design.one.NlpRule;
import com.hgdata.design.one.RuleSet;
public class RuleSets {
private RuleSets() {
}
public static RuleSet isValidLocation() {
RuleSet ruleSet = new RuleSet();
ruleSet.add(NlpRule.CITY_NOT_NULL);
ruleSet.add(NlpRule.STATE_NOT_NULL);
ruleSet.add(NlpRule.COUNTRY_US);
ruleSet.add(NlpRule.STATE_ABBREVIATED);
return ruleSet;
}
}
Main.java
public class Main {
public static void main(String... args) {
String location = "Santa Barbara,CA,USA";
RuleSet ruleSet = RuleSets.isValidLocation();
try {
boolean isValid = (boolean) ruleSet.apply(location);
System.out.println(isValid);
} catch (Exception e) {
e.getMessage();
}
}
}
Better Design Approach/Pattern ?
As you can see, design 2 gets rid of the interface and enum. It instead uses an abstract class. I am still wondering if there is a better design pattern/approach to implement the same.
Instantiation using initializer blocks:
Now in case of both designs above. Say, if I need to instantiate an external class to use it inside my apply logic, then I am forced to use initializer blocks which I am not totally aware whether is a good practice. See example for such a scenario below:
Design 1:
...
STATE_ABBREVIATED(new Rule() {
private CustomParser parser;
{
parser = new CustomParser();
}
#Override
public Object apply(Object object) {
String location = (String) object;
location = parser.parse(location);
String state = location.split(",")[1];
if (state.length() == 2) {
return true;
}
return false;
}
});
...
Design 2:
...
public final static NlpRule STATE_ABBREVIATED = new NlpRule() {
private CustomParser parser;
{
parser = new CustomParser();
}
public Object apply(Object object) {
String location = (String) object;
location = parser.parse(location);
String state = location.split(",")[1];
if (state.length() == 2) {
return true;
}
return false;
}
};
...
Java experts please cast some light! Also please pinpoint if you find any flaws in the above two designs. I need to know the pros and cons associated with each of the designs to help me make the right decision. I am looking into lambdas, predicates and several other patterns as suggested by some users in the comments.
This is an interesting question with many possible answers. To some extent the solution is going to depend on personal preference. I have often come across similar problems and have the following recommendations. Note that these work for me but might not suit your needs.
Use enum. In the long term I feel they have a lot of advantages over private static members in terms of their error checking and the useful containers (EnumSet etc.) that can use them efficiently.
Use interfaces over abstract classes. Before Java 8 there were useful reasons to use abstract classes. With default members there are now no good reasons (just my opinion - I'm sure others will disagree). An enum can implement an interface.
In Java 8 the logic associated with each 'rule' can be embedded in a lambda expression which makes the initialization code for your enums clearer.
Keep lambdas very short - just one or two commands at the most (and preferably one expression without a block). This means splitting any complex logic into a separate methods.
Use separate enums to classify your rules. There's no good reason to put them all into one and by splitting them out you can make the constructors simple by having exactly the lambda expressions relevant to their domain. See my example below to see what I mean.
If you have hierarchies of rules, use the composite design pattern. It's flexible and robust.
So putting those recommendations together I would suggest something like:
interface LocationRule{
boolean isValid(Location location);
}
enum ValidValueRule implements LocationRule {
STATE_NOT_NULL(location -> location.getState() != null),
CITY_NOT_NULL(location -> location.getCity() != null);
private final Predicate<Location> locationPredicate;
ValidValueRule(Predicate<Location> locationPredicate) {
this.locationPredicate = locationPredicate;
}
public boolean isValid(Location location) {
return locationPredicate.test(location);
}
}
enum StateSizeRule implements LocationRule {
IS_BIG_STATE(size -> size > 1000000),
IS_SMALL_STATE(size -> size < 1000);
private final Predicate<Integer> sizePredicate;
StateSize(Predicate<Integer> sizePredicate) {
this.sizePredicate = sizePredicate;
}
public boolean isValid(Location location) {
return sizePredicate.test(location.getState().getSize());
}
}
class AllPassRule implements LocationRule {
private final List<LocationRule > rules = new ArrayList<>();
public void addRule(LocationRule rule) {
rules.add(rule);
}
public boolean isValid(Location location) {
return rules.stream().allMatch(rule -> rule.isValid(location));
}
}
class AnyPassRule implements LocationRule {
private final List<LocationRule > rules = new ArrayList<>();
public void addRule(LocationRule rule) {
rules.add(rule);
}
public boolean isValid(Location location) {
return rules.stream().anyMatch(rule -> rule.isValid(location));
}
}
class NegateRule implements LocationRule {
private final Rule rule;
public NegateRule(Rule rule) {
this.rule = rule;
}
public boolean isValid(Location location) {
return !rule.isValid(location);
}
}
So, for example, to implement a rule that locations must either be in a city or in a state that isn't small:
AnyPassRule cityOrNonSmallState = new AnyPassRule();
cityOrNonSmallState.addRule(ValidValueRule.CITY_NOT_NULL);
cityOrNonSmallState.addRule(new NegateRule(StateSize.IS_SMALL_STATE));
return cityOrNonSmallState.isValid(location);
There's lots of (open source) Java rule engines out there already - check out http://java-source.net/open-source/rule-engines & http://drools.org/
You could start with using/examining the source for one of those (taking note of where it doesn't meet your requirements) and go from there.
Another possible answer is to use a DSL parser to valid your rule, in function programming language, there is thing called parser combinator which could build a larger parser(rule set) from different basic parser(rule). The good point of this way is the flexibility, the cons is every time your want to change your rule set, you have to re-code.
Interface with static fields:
public interface NlpRule
{
Object apply(Object object);
NlpRule CITY_NOT_NULL = object ->
{
String location = (String) object;
String city = location.split(",")[0];
return ...true/false;
};
// etc.
Some may prefer methods over functional objects
public interface NlpRule
{
Object apply(Object object);
static boolean cityNotNull(Object object) // java8: static method in interface
{
String location = (String) object;
String city = location.split(",")[0];
return ...true/false;
};
// etc.
}
// use method reference as functional object
NlpRule rule = NlpRule::cityNotNull;
ruleset.add( NlpRule::cityNotNull );
Or you could have both method and field
public interface NlpRule
{
Object apply(Object object);
NlpRule CITY_NOT_NULL = NlpRule::cityNotNull;
static boolean cityNotNull(Object object)
{
...
};
The example rules are all String->boolean, not sure why NlpRule is Object->Object. If the rules could indeed accept/return different types, you should probably generify NlpRule<T,R>.
The CustomParser can be stored in a package-private helper class
class NlpRuleHelper
{
static final CustomParser parser = new CustomParser();
}
--
public interface NlpRule
...
NlpRule STATE_ABBREVIATED = object ->
{
...
location = NlpRuleHelper.parser.parse(location);
I think you have added at least one layer of unnecessary code. Remember that enum can also implement interfaces and can even have abstract methods.
/**
* I don't like `Object` so I will adjust.
*/
public interface Rule {
public boolean pass(String s);
}
/**
* All pass country codes.
*/
public enum ValidCountry {
US, USA;
public static Set<String> all = new HashSet<>();
static {
for (ValidCountry c : ValidCountry.values()) {
all.add(c.name());
}
}
}
public enum NlpRule implements Rule {
CITY_NOT_NULL {
#Override
public boolean pass(String location) {
return location.split(",")[0] != null;
}
},
STATE_NOT_NULL {
#Override
public boolean pass(String location) {
return location.split(",")[1] != null;
}
},
COUNTRY_US {
#Override
public boolean pass(String location) {
return ValidCountry.all.contains(location.split(",")[2]);
}
},
STATE_ABBREVIATED {
#Override
public boolean pass(String location) {
return location.split(",")[1].length() == 2;
}
};
/**
* You can even make Sets of them.
*/
static Set<NlpRule> isValidLocation = EnumSet.of(CITY_NOT_NULL, STATE_NOT_NULL, COUNTRY_US, STATE_ABBREVIATED);
}
public void test() {
String test = "Santa Barbara,CA,USA";
for (Rule r : NlpRule.isValidLocation) {
boolean pass = r.pass(test);
System.out.println(r + "(\"" + test + "\") - " + (pass ? "passes" : "FAILS"));
}
}
I have a enum defined like this and I would like to be able to obtain the strings for the individual statuses. How should I write such a method?
I can get the int values of the statuses but would like the option of getting the string values from the ints as well.
public enum Status {
PAUSE(0),
START(1),
STOP(2);
private final int value;
private Status(int value) {
this.value = value
}
public int getValue() {
return value;
}
}
if status is of type Status enum, status.name() will give you its defined name.
You can use values() method:
For instance Status.values()[0] will return PAUSE in your case, if you print it, toString() will be called and "PAUSE" will be printed.
Use default method name() as given bellows
public enum Category {
ONE("one"),
TWO ("two"),
THREE("three");
private final String name;
Category(String s) {
name = s;
}
}
public class Main {
public static void main(String[] args) throws Exception {
System.out.println(Category.ONE.name());
}
}
You can add this method to your Status enum:
public static String getStringValueFromInt(int i) {
for (Status status : Status.values()) {
if (status.getValue() == i) {
return status.toString();
}
}
// throw an IllegalArgumentException or return null
throw new IllegalArgumentException("the given number doesn't match any Status.");
}
public static void main(String[] args) {
System.out.println(Status.getStringValueFromInt(1)); // OUTPUT: START
}
I believe enum have a .name() in its API, pretty simple to use like this example:
private int security;
public String security(){ return Security.values()[security].name(); }
public void setSecurity(int security){ this.security = security; }
private enum Security {
low,
high
}
With this you can simply call
yourObject.security()
and it returns high/low as String, in this example
You can use custom values() method:
public enum SortType
{
Scored, Lasted;
public int value(){
return this == Lasted ? 1:0;
}
}