diff --git a/project.clj b/project.clj index bb66350..4ae7101 100644 --- a/project.clj +++ b/project.clj @@ -6,7 +6,8 @@ :dependencies [[org.clojure/clojure "1.4.0"] [org.clojure/tools.cli "0.2.2"] [org.javassist/javassist "3.16.1-GA"] - [net.sf.scannotation/scannotation "1.0.2" :exclusions [javassist]]] + [net.sf.scannotation/scannotation "1.0.2" :exclusions [javassist]] + [crustimoney "0.1.0"]] :java-source-paths ["src-java"] :main gluer.core :aot [gluer.agent gluer.runtime] diff --git a/src-java/test/Main.java b/src-java/test/Main.java index 3e42177..7e71270 100644 --- a/src-java/test/Main.java +++ b/src-java/test/Main.java @@ -9,29 +9,29 @@ public class Main { - - private SuperSuperA superSuperA; - private SuperA superA; - private A a; - private A twice; - private SubA subA; - - public Main(final String[] args) throws Exception { - System.out.println(" Starting application..."); - for (final String arg : args) { - System.out.println(" Calling method "+ arg +"() ..."); - final Object fieldObject = - getClass().getDeclaredField(arg.split("\\.")[0]).get(this); - final Method objMethod = - fieldObject.getClass().getMethod(arg.split("\\.")[1], new Class[0]); - objMethod.invoke(fieldObject); - } - System.out.println(" Exiting application."); - } - - - public static void main(final String[] args) throws Exception { - new Main(args); - } - -} \ No newline at end of file + + private SuperSuperA superSuperA; + private SuperA superA; + private A a; + private A twice; + private SubA subA; + + public Main(final String[] args) throws Exception { + System.out.println(" Starting application..."); + for (final String arg : args) { + System.out.println(" Calling method "+ arg +"() ..."); + final Object fieldObject = + getClass().getDeclaredField(arg.split("\\.")[0]).get(this); + final Method objMethod = + fieldObject.getClass().getMethod(arg.split("\\.")[1], new Class[0]); + objMethod.invoke(fieldObject); + } + System.out.println(" Exiting application."); + } + + + public static void main(final String[] args) throws Exception { + new Main(args); + } + +} diff --git a/src-java/test/bind.gluer b/src-java/test/bind.gluer index c4293ba..40a4a4a 100644 --- a/src-java/test/bind.gluer +++ b/src-java/test/bind.gluer @@ -8,7 +8,3 @@ associate field test.Main.superSuperA with single test.modelb.SubSubB using test declare precedence test.adapter.TwiceBtoA1 over test.adapter.TwiceBtoA2 declare precedence test.adapter.TwiceBtoA2 over test.adapter.TwiceBtoA3 - -declare precedence test.adapter.TwiceBtoA3 over test.adapter.TwiceBtoA1 - -associate field test.Main.twice with new test.modelb.TwiceB \ No newline at end of file diff --git a/src/gluer/clauses.clj b/src/gluer/clauses.clj index fbd4e41..1799e64 100644 --- a/src/gluer/clauses.clj +++ b/src/gluer/clauses.clj @@ -11,14 +11,14 @@ ;;;; a clause, one for determining the type of the clause and one for generating ;;;; or injecting code. ;;;; -;;;; The multi-method selection is based on the node-types in the parsing -;;;; result. +;;;; The multi-method selection is based on the node-types in the parsing +;;;; result. (ns gluer.clauses (:require [gluer.resources :as r]) (:use [gluer.logging]) (:import [java.io ByteArrayInputStream] - [javassist CtClass ClassPool CtField CtNewMethod])) + [javassist CtClass ClassPool CtField CtNewMethod Modifier])) ;;; The multi-methods to implement, for a clause. @@ -33,7 +33,7 @@ (fn [this-association that-association] (ffirst (:where this-association)))) (defmulti type-of-where - "Given a clause, returns the fully qualified name of the (base) type + "Given a clause, returns the fully qualified name of the (base) type of the clause." (fn [where-clause] (ffirst where-clause))) @@ -46,7 +46,7 @@ (defmulti inject-where "Based on a where-clause and a class model (ctclass), inject the retrieval-code into the class. Since the ctclass is stateful, nothing needs to be returned." - (fn [where-clause ctclass retrieval-code] + (fn [where-clause ctclass retrieval-code] (ffirst where-clause))) @@ -70,7 +70,7 @@ ;;; Helper functions. (defn- full-class-name - "Returns the fully qualified class name, based on a package name and class + "Returns the fully qualified class name, based on a package name and class name. The package may be nil." [package class-name] (str package (when package ".") class-name)) @@ -113,8 +113,8 @@ nil (catch javassist.CannotCompileException cce (subs (.getMessage cce) 15)) - (finally - (.detach ctclass) + (finally + (.detach ctclass) (.defrost ctclass))))) (defmethod check-what :what-clause-call @@ -123,7 +123,7 @@ class-name (full-class-name (nth match 1) (nth match 2))] (if-let [ctclass (r/class-by-name class-name)] (check-expression word) - (format "Class %s in the `call' clause not found. Please check the name or classpath." + (format "Class %s in the `call' clause not found. Please check the name or classpath." class-name)))) (defmethod type-of-what :what-clause-call @@ -133,7 +133,7 @@ method-name (nth match 3) ctclass (r/class-by-name class-name) method (first (filter #(= (.getName %) method-name) (.getMethods ctclass)))] - (.getName (.getReturnType method)))) + (.getName (.getReturnType method)))) (defmethod generate-what :what-clause-call [association] @@ -157,7 +157,7 @@ (defmethod generate-what :what-clause-single [association] - (format "gluer.Runtime.single(\"%s\")" + (format "gluer.Runtime.single(\"%s\")" (get-in association [:what :what-clause-single :class :word]))) @@ -170,8 +170,11 @@ field-name (nth match 3)] (if-let [ctclass (r/class-by-name class-name)] (try - (let [field (.getDeclaredField ctclass field-name)] - nil) ;--- Check if field has init code or injection is overwritten in a constructor? + (let [field (.getDeclaredField ctclass field-name) + modifiers (.getModifiers field)] + (if (or (Modifier/isStatic modifiers) (Modifier/isFinal modifiers)) + (format "Field %s.%s cannot be static or final." class-name field-name) + nil)) ;--- Check if field has init code or injection is overwritten in a constructor? (catch javassist.NotFoundException nfe (format "Class %s does not have a field named %s." class-name field-name))) (format "Class %s cannot be found. Please check the name or classpath." class-name)))) @@ -180,7 +183,7 @@ [this that] (when-let [that-field (get-in that [:where :where-clause-field :field :word])] (let [this-field (get-in this [:where :where-clause-field :field :word])] - (when (= this-field that-field) + (when (= this-field that-field) (format "The field '%s' has conflicting injections." this-field))))) (defmethod type-of-where :where-clause-field @@ -204,7 +207,7 @@ field-name (nth match 3) constructor-code (format "_inject_%1$s();" field-name) field-code (format "private boolean _%1$s_injected;" field-name) - method-code (format + method-code (format (str "\nprivate void _inject_%1$s() {\n" " if (! this._%1$s_injected) {\n" " this.%1$s = %2$s;\n" diff --git a/test/gluer/core_test.clj b/test/gluer/core_test.clj index 5812f63..59685d5 100644 --- a/test/gluer/core_test.clj +++ b/test/gluer/core_test.clj @@ -9,7 +9,7 @@ ; : means adaptation (from B to A) ; ; SuperSuperA -; ^ +; ^ ; SuperA .. SuperB ; ^ ``--.. ^ ; ,..- A ,,,,,,,,,,,;;; B < TwiceB @@ -20,7 +20,7 @@ ; : : ; `-.........2x.............-` -(def supertypes +(def supertypes {"SuperB" [#{"java.lang.Object"}] "B" [#{"SuperB"} #{"java.lang.Object"}] "SubB" [#{"B"} #{"SuperB"} #{"java.lang.Object"}] @@ -32,7 +32,7 @@ "A" [#{"SuperA"} #{"SuperSuperA"} #{"java.lang.Object"}] "SubA" [#{"A"} #{"SuperA"} #{"SuperSuperA"} #{"java.lang.Object"}]}) -(def adapters +(def adapters {"BtoA" {:adapts-from #{"B"} :adapts-to [#{"A"} #{"SuperA"} #{"SuperSuperA"} #{"java.lang.Object"}]} "BtoSuperA" {:adapts-from #{"B"} @@ -66,10 +66,10 @@ ; No match. No adapter from a type (or a supertype of from). ; Might also be a warning, if adapters are found for subtypes of from. ; Or, this might be a reason for abstract Adapters. - "SuperB" "SuperA" + "SuperB" "SuperA" ; Equal matches conflict. "TwiceB" "A")) (testing "Testing warnings." - (are [from to] (not (nil? (:warning (get-adapter-for from to adapters)))) + #_(are [from to] (not (nil? (:warning (get-adapter-for from to adapters)))) ; Possible runtime conflict error for subtype of from. "B" "A")))))