Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Issue446: Bean accessors don't account for IndexedPropertyDescriptors #449

Merged
merged 6 commits into from
Feb 18, 2020

Conversation

EthanEChristian
Copy link
Contributor

@EthanEChristian EthanEChristian commented Feb 1, 2020

A PR for #446

project.clj Outdated
@@ -78,6 +78,9 @@
(some->> x :ns ns-name str (re-matches (re-pattern (apply str patterns)))))))
:generative (fn [x] (some->> x :ns ns-name str (re-matches #"^clara\.generative.*")))
:performance (fn [x] (some->> x :ns ns-name str (re-matches #"^clara\.performance.*")))}

;; Remove any "Test Facts" from being included in the jar.
:jar-exclusions [#".*TestFact\.(java|class)"]
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

They really shouldn't even be in the "main" src path, but that's a topic for another build related issue I think.

Any reason this was added in this particular PR though?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

removed with:
b41ffee

/**
* A Java Pojo for the express purpose of testing the behavior of compilation and execution of rules.
*
* This class should not be included in the released artifact, if it did make it into a released artifact it should be
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why can't it be under src/test/java instead? ie, a dev-time-only :source-paths?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed, I don't understand why this needs to be in the main source path and then removed from the jar afterward rather than just put in a test source path from the start.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My lein is not that strong, but yeah that works:
b41ffee


:sessions [empty-session [kansas-rule string-query] {}]}

(let [locs (make-array String 2)]
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You could use doto around make-array to do the aset's all in one go and make it seem somewhat more "functional/immutable" in style

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done:
1a12065

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1

;; see https://github.com/cerner/clara-rules/issues/446
(tu/def-rules-test test-basic-rule
{:rules [kansas-rule [[[BeanTestFact
(= ?locs locations)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So would direct field access on roadConditions not work since it has no standard accessor?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's what I'd think yes. A test that an actual invocation of the indexed accessor in a rule for the property without a standard accessor still works might be nice to have and wouldn't be hard to create but isn't crucial. I realize it should still pass with this implementation, I just tend to prefer having tests be implementation agnostic where possible.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

added a test demonstrating that a compilation error is thrown when trying to use the standard accessor:
1a12065

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1

@@ -31,7 +31,8 @@
Accumulator
ISystemFact]
[java.beans
PropertyDescriptor]
PropertyDescriptor
IndexedPropertyDescriptor]
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This new import does not seem like it is needed.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

cleaned up:
27e120f

Copy link
Collaborator

@WilliamParker WilliamParker left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A few minor suggestions and something to check re reflection but this looks basically sound to me.

;; the accessor as we will not know how to retrieve the value. see https://github.com/cerner/clara-rules/issues/446
:when read-method]
[(symbol (string/replace (.getName property) #"_" "-")) ; Replace underscore with idiomatic dash.
(symbol (str "." (.getName read-method)))])))
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You'll want to be careful that nothing here adds new reflection. Perhaps compile a session (thus doing evals) with reflection warnings turned on. This would be a good test to have actually though perhaps a bit out of scope here; as far as I know we don't have a test for this.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Adding

:global-vars {*warn-on-reflection* true}

to the project and building doesn't show this as a reflection.
To test that this is correct, i removed the type hint for PropertyDescriptor and i get the following:

Reflection warning, clara/rules/compiler.clj:179:33 - reference to field getReadMethod on java.lang.Object can't be resolved.
Reflection warning, clara/rules/compiler.clj:183:36 - reference to field getName on java.lang.Object can't be resolved.
Reflection warning, clara/rules/compiler.clj:184:29 - reference to field getName can't be resolved.
Reflection warning, clara/rules/compiler.clj:179:33 - reference to field getReadMethod can't be resolved.
Reflection warning, clara/rules/compiler.clj:183:36 - reference to field getName can't be resolved.
Reflection warning, clara/rules/compiler.clj:184:29 - reference to field getName can't be resolved.

So, i think we are good for this example.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep, doesn't look like reflection.

I think we should just have

:global-vars {*warn-on-reflection* true}

at the top-level of our lein project.clj though in general

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why not:
dc754f9

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To be clear, my concern wasn't necessarily with reflection warnings in Clara itself but rather with reflection when invoking accessors on Java objects. For example:

(defrule testrule
    [JavaBeanWithFieldA (= a "some value")]
   =>
  ;; do something
)

reflecting when invoking the .getA method behind the scenes. However in any case if that were happening I'd expect to see more warnings in the Travis build with global reflection warnings enabled - in particular, warnings interspersed through test execution when eval calls build rule networks. So +1.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, yeah that makes sense. I believe the reason that the rules network fns don't experience reflection is because we add the metadata a bit later:
https://github.com/cerner/clara-rules/blob/1bafa05c2502eb452bdd765c1b45c158725f575e/src/main/clojure/clara/rules/compiler.clj#L390

/**
* A Java Pojo for the express purpose of testing the behavior of compilation and execution of rules.
*
* This class should not be included in the released artifact, if it did make it into a released artifact it should be
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed, I don't understand why this needs to be in the main source path and then removed from the jar afterward rather than just put in a test source path from the start.

;; see https://github.com/cerner/clara-rules/issues/446
(tu/def-rules-test test-basic-rule
{:rules [kansas-rule [[[BeanTestFact
(= ?locs locations)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's what I'd think yes. A test that an actual invocation of the indexed accessor in a rule for the property without a standard accessor still works might be nice to have and wouldn't be hard to create but isn't crucial. I realize it should still pass with this implementation, I just tend to prefer having tests be implementation agnostic where possible.

[clojure.test :refer [is deftest run-tests testing use-fixtures]])
(:import [clara.test.facts
BeanTestFact]))

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This test seems like it could go in the test_java namespace as well, but I don't have strong feelings about it.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was on the fence about that, I kind of felt like the test_java namespace was testing the Java apis rather than the usage of java roots in the rulebase and thats why i created a new namespace.


;; A test to demonstrate that a Pojo with indexed property accessors can be used as an alpha root in a session,
;; see https://github.com/cerner/clara-rules/issues/446
(tu/def-rules-test test-basic-rule
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note that using def-rules-test isn't really needed here since this presumably isn't going to be tested in ClojureScript, but it doesn't do any harm.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I did this for consistency

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Might as well test all that we can test on all platforms.

(rules/fire-rules)
(rules/query string-query)))]
(is (= 1 (count session-strings)))
(is (contains? session-strings "Kansas Exists")))))
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A slightly more concise option:

(let [session-strings (map :?s (-> empty-session
                                    (rules/insert (BeanTestFact. locs))
                                    (rules/fire-rules)
                                    (rules/query string-query)))]
      (is (= ["Kansas"] session-strings)))

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

updated:
1a12065

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1

return locations[pos];
}

// Partial Indexed property accessor, ie. no standard accessor
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps add the issue link to this comment as well.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

added:
2d81c3e

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1

@EthanEChristian EthanEChristian self-assigned this Feb 13, 2020
project.clj Outdated
@@ -6,7 +6,9 @@
:dependencies [[org.clojure/clojure "1.7.0"]
[prismatic/schema "1.1.6"]]
:profiles {:dev {:dependencies [[org.clojure/math.combinatorics "0.1.3"]
[org.clojure/data.fressian "0.2.1"]]}
[org.clojure/data.fressian "0.2.1"]]
:java-source-paths ["src/main/java"
Copy link
Collaborator

@mrrodriguez mrrodriguez Feb 13, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You don't have to repeat "src/main/java". It's already at the root under :java-source-paths. :dev profile will merge on top of that.
lein merges collections together if you don't have metadata on them like :replace or :displace.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

updated:
dc754f9

@@ -3,17 +3,11 @@
This is the Clara rules compiler, translating raw data structures into compiled versions and functions.
Most users should use only the clara.rules namespace."
(:require [clara.rules.engine :as eng]
[clara.rules.listener :as listener]
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Were these just unused ns's to clean up?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, might as well clean up while im here

Copy link
Collaborator

@mrrodriguez mrrodriguez left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's a yes from me dawg

Copy link
Collaborator

@WilliamParker WilliamParker left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1 to merge

;; the accessor as we will not know how to retrieve the value. see https://github.com/cerner/clara-rules/issues/446
:when read-method]
[(symbol (string/replace (.getName property) #"_" "-")) ; Replace underscore with idiomatic dash.
(symbol (str "." (.getName read-method)))])))
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To be clear, my concern wasn't necessarily with reflection warnings in Clara itself but rather with reflection when invoking accessors on Java objects. For example:

(defrule testrule
    [JavaBeanWithFieldA (= a "some value")]
   =>
  ;; do something
)

reflecting when invoking the .getA method behind the scenes. However in any case if that were happening I'd expect to see more warnings in the Travis build with global reflection warnings enabled - in particular, warnings interspersed through test execution when eval calls build rule networks. So +1.

return locations[pos];
}

// Partial Indexed property accessor, ie. no standard accessor
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1

;; see https://github.com/cerner/clara-rules/issues/446
(tu/def-rules-test test-basic-rule
{:rules [kansas-rule [[[BeanTestFact
(= ?locs locations)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1


:sessions [empty-session [kansas-rule string-query] {}]}

(let [locs (make-array String 2)]
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1

(rules/fire-rules)
(rules/query string-query)))]
(is (= 1 (count session-strings)))
(is (contains? session-strings "Kansas Exists")))))
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1

@EthanEChristian EthanEChristian merged commit bda21fe into oracle-samples:master Feb 18, 2020
@EthanEChristian EthanEChristian deleted the Issue_446 branch February 18, 2020 00:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants