Writing Integration Test of ExpressionVisitor with Olingo / ODATA 4 - java

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.

Related

Jackson custom deserializer null codec

I have wrote custom deserializer for my type, which is represented as interface Attachment and there are two implementions of this interface Photo and Video.
When parsing I recognize them from json using discriminator field.
Now I'm facing problem when jp.getCodec() returns null, leading
to null pointer exception
Why this is happining and how to fix it?
public class AttachmentDeserializer extends StdDeserializer<Attachment> {
ObjectMapper objectMapper = new ObjectMapper();
public AttachmentDeserializer() {
this(null);
objectMapper.registerModule(new Jdk8Module());
}
public AttachmentDeserializer(Class<Attachment> t) {
super(t);
objectMapper.registerModule(new Jdk8Module());
}
#Override
public Attachment deserialize(JsonParser jp, DeserializationContext ctxt)
throws IOException, JsonProcessingException {
JsonNode node = jp.getCodec().readTree(jp);
String type = node.get("type").asText();
switch (type) {
case "photo":
return new AttachmentPhoto(
node.get("t").asInt(),
objectMapper.readValue(node.get("photo").traverse(), Photo.class));
case "video":
return new AttachmentVideo(
node.get("t").asInt(),
objectMapper.readValue(node.get("video").traverse(), Video.class));
default:
throw ctxt.weirdStringException("type", Attachment.class, "Unknown discriminator");
}
}
}
The attachmentPhoto code:
#JsonNaming(PropertyNamingStrategy.SnakeCaseStrategy.class)
public class AttachmentPhoto implements Attachment {
private Photo photo;
public Attachments what() {
return Attachments.ATTACHMENT_PHOTO;
}
public String getDiscriminator() {
return "photo";
}
public AttachmentPhoto() {}
public AttachmentPhoto(Photo photo) {
this.photo = photo;
}
public Photo getPhoto() {
return this.photo;
}
public AttachmentPhoto setPhoto(Photo v) {
this.photo = v;
return this;
}
public boolean isAttachmentPhoto() {
return true;
}
public AttachmentPhoto asAttachmentPhoto() {
return this;
}
public boolean isAttachmentVideo() {
return false;
}
public AttachmentVideo asAttachmentVideo() {
throw new IllegalStateException("Not a $stName: " + this);
}
#Override
public boolean equals(Object thatObj) {
if (this == thatObj) return true;
if (!(thatObj instanceof AttachmentPhoto)) return false;
AttachmentPhoto that = (AttachmentPhoto) thatObj;
return this.photo.equals(that.photo);
}
#Override
public String toString() {
return "AttachmentPhoto{" + "photo=" + this.photo + '}';
}
}
Your default constructor looks very suspicious for two reasons, first it calls the second constructor with null class type which then passes the null type to the superclass hence the overridden generic method is messed up when this constructor is used. Secondly, it does no useful work since it already calls the other constructor that initializes objectMapper. You should remove the first constructor and remain with just the typed one and initialize your deserializer using that.

Implementing a kotlin interface in java

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.

how can I call a custom hamcrest matcher?

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

What is the an effective design pattern/style for designing a rule engine in 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"));
}
}

Validate an XML against an XSD in Java / Getting a hold of the schemaLocation

How can one validate an XML file using an XSD in Java? We don't know the schema in advance. I would like to be able to get the schemaLocation, download the XSD, cache it and then perform the actual validation.
The problem is, that with javax.xml.parsers.DocumentBuilder/DocumentBuilderFactory classes I can't seem to be able to get a hold of the schemaLocation in advance. What's the trick for this? Which classes should I look into?
Perhaps there's a more suitable API I can use? The whole problem is that we need to validate dynamically, without (necessarily) having the XSDs locally.
How could one get a hold of the URL of schemaLocation defined in the XSD file?
I know you can set features/attributes, but that's a different thing. I need to get the schemaLocation from the XSD first.
Please advise!
Given that you are using Xerces (or JDK default), have you tried setting this feature to true on the factory: http://apache.org/xml/features/validation/schema. There are other features that you can play with regarding schemas: http://xerces.apache.org/xerces2-j/features.html
UPDATE 2 (for caching):
Implement a org.w3c.dom.ls.LSResourceResolver and set this on the SchemaFactory using the setResourceResolver method. This resolver would either get the schema from cache or fetch it from wherever the location refers to.
UPDATE 3:
LSResourceresolver example (which I think will be a good starting point for you):
/**
* Resolves resources from a base URL
*/
public class URLBasedResourceResolver implements LSResourceResolver {
private static final Logger log = LoggerFactory
.getLogger(URLBasedResourceResolver.class);
private final URI base;
private final Map<URI, String> nsmap;
public URLBasedResourceResolver(URL base, Map<URI, String> nsmap)
throws URISyntaxException {
super();
this.base = base.toURI();
this.nsmap = nsmap;
}
#Override
public LSInput resolveResource(String type, String namespaceURI,
String publicId, String systemId, String baseURI) {
if (log.isDebugEnabled()) {
String msg = String
.format("Resolve: type=%s, ns=%s, publicId=%s, systemId=%s, baseUri=%s.",
type, namespaceURI, publicId, systemId, baseURI);
log.debug(msg);
}
if (type.equals(XMLConstants.W3C_XML_SCHEMA_NS_URI)) {
if (namespaceURI != null) {
try {
URI ns = new URI(namespaceURI);
if (nsmap.containsKey(ns))
return new MyLSInput(base.resolve(nsmap.get(ns)));
} catch (URISyntaxException e) {
// ok
}
}
}
return null;
}
}
The implementation of MyLSInput is really boring:
class MyLSInput implements LSInput {
private final URI url;
public MyLSInput(URI url) {
super();
this.url = url;
}
#Override
public Reader getCharacterStream() {
return null;
}
#Override
public void setCharacterStream(Reader characterStream) {
}
#Override
public InputStream getByteStream() {
return null;
}
#Override
public void setByteStream(InputStream byteStream) {
}
#Override
public String getStringData() {
return null;
}
#Override
public void setStringData(String stringData) {
}
#Override
public String getSystemId() {
return url.toASCIIString();
}
#Override
public void setSystemId(String systemId) {
}
#Override
public String getPublicId() {
return null;
}
#Override
public void setPublicId(String publicId) {
}
#Override
public String getBaseURI() {
return null;
}
#Override
public void setBaseURI(String baseURI) {
}
#Override
public String getEncoding() {
return null;
}
#Override
public void setEncoding(String encoding) {
}
#Override
public boolean getCertifiedText() {
return false;
}
#Override
public void setCertifiedText(boolean certifiedText) {
}
}

Categories

Resources