├── .gitignore
├── LICENSE
├── README.md
├── classreloading.iml
├── data
└── example5
│ ├── config.properties
│ └── web
│ ├── angular_1.3.1
│ ├── angular-animate.min.js
│ ├── angular-resource.min.js
│ ├── angular-sanitize.min.js
│ ├── angular-ui-router.min.js
│ ├── angular.js
│ └── angular.min.js
│ ├── bootstrap_3.2.0
│ ├── bootstrap.min.css
│ ├── bootstrap.min.js
│ └── ui-bootstrap-tpls-0.11.2.min.js
│ ├── favicon.ico
│ ├── fonts
│ ├── FontAwesome.otf
│ ├── fontawesome-webfont.eot
│ ├── fontawesome-webfont.svg
│ ├── fontawesome-webfont.ttf
│ ├── fontawesome-webfont.woff
│ ├── glyphicons-halflings-regular.eot
│ ├── glyphicons-halflings-regular.svg
│ ├── glyphicons-halflings-regular.ttf
│ └── glyphicons-halflings-regular.woff
│ ├── jquery-2.1.1
│ └── jquery-2.1.1.min.js
│ └── spa
│ ├── app.js
│ ├── hello
│ ├── AddContactModal.jade
│ ├── Hello.jade
│ └── Hello.js
│ └── spa.jade
├── pom.xml
├── push_github.cmd
├── run_example1.bat
├── run_example2.bat
├── run_example3.bat
├── run_example4.bat
├── run_example5.bat
└── src
└── main
├── ai
├── 1_2_loaders.ai
├── 2_many_loaders.ai
├── 3_context_reloading.ai
├── 4_persisting_connection.ai
├── 5_reloading_web_context.ai
└── 5_web_app.ai
├── java
└── qj
│ ├── blog
│ └── classreloading
│ │ ├── example1
│ │ └── StaticInt.java
│ │ ├── example2
│ │ └── ReloadingContinuously.java
│ │ ├── example3
│ │ └── ContextReloading.java
│ │ ├── example4
│ │ ├── KeepConnectionPool.java
│ │ ├── crossing
│ │ │ ├── Connection.java
│ │ │ └── ConnectionPool.java
│ │ └── reloadable
│ │ │ ├── Context.java
│ │ │ └── UserService.java
│ │ └── example5
│ │ ├── LittlePhoneBookMain.java
│ │ └── reloadable
│ │ ├── Context.java
│ │ ├── dao
│ │ └── ContactDAO.java
│ │ ├── model
│ │ └── Contact.java
│ │ └── servlet
│ │ ├── ContactServlet.java
│ │ └── JadeServlet.java
│ ├── tool
│ ├── sql
│ │ ├── Builder.java
│ │ ├── SQLUtil.java
│ │ └── Template.java
│ └── web
│ │ ├── ReloadingContext.java
│ │ ├── ReloadingWebContext.java
│ │ └── ResourceFilter.java
│ └── util
│ ├── Cols.java
│ ├── FileUtil.java
│ ├── IOUtil.java
│ ├── NameCaseUtil.java
│ ├── ObjectUtil.java
│ ├── PropertiesUtil.java
│ ├── ReflectUtil.java
│ ├── RegexUtil.java
│ ├── StringChange.java
│ ├── StringUtil.java
│ ├── SystemUtil.java
│ ├── ThreadUtil.java
│ ├── funct
│ ├── F0.java
│ ├── F1.java
│ ├── F2.java
│ ├── Fs.java
│ ├── FsGenerated.java
│ ├── P0.java
│ ├── P1.java
│ ├── P2.java
│ └── P3.java
│ ├── lang
│ ├── AggressiveClassLoader.java
│ ├── DynamicClassLoader.java
│ └── ExceptingClassLoader.java
│ └── math
│ └── Range.java
└── kramdown
├── v1.kd
├── v2.kd
├── v3
├── content.md
└── outline.md
└── v4
├── content.md
└── v4-NM1.txt
/.gitignore:
--------------------------------------------------------------------------------
1 | target/
2 | .idea/
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License
2 |
3 | Copyright (c) 2010-2016 Quan Le. http://quanla.github.io/
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in
13 | all copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 | THE SOFTWARE.
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 | ### If you are using Eclipse:
3 | - Run command: "mvn eclipse:eclipse" to generate Eclipse's project files
4 | - Set your output path to "target/classes"
5 |
6 | ### If you are using IntelliJ:
7 |
8 | - Set your output path to "target/classes"
9 | - Import the project's pom file
10 | - Intellij will not auto-compile when you are running any example, so you have to choose either:
11 | - Run the examples inside IntelliJ then you have to compile the class manually with (Alt+B E)
12 | - Run the examples outside IntelliJ with the run_example*.bat
13 |
14 | 下文介绍比较详细
15 | https://www.toptal.com/java/java-wizardry-101-a-guide-to-java-class-reloading
16 |
--------------------------------------------------------------------------------
/classreloading.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
--------------------------------------------------------------------------------
/data/example5/config.properties:
--------------------------------------------------------------------------------
1 | web.port=1080
2 |
3 | db.driver=org.sqlite.JDBC
4 |
5 | db.url=jdbc:sqlite::memory:
6 |
7 |
8 |
--------------------------------------------------------------------------------
/data/example5/web/angular_1.3.1/angular-animate.min.js:
--------------------------------------------------------------------------------
1 | /*
2 | AngularJS v1.3.1
3 | (c) 2010-2014 Google, Inc. http://angularjs.org
4 | License: MIT
5 | */
6 | (function(M,f,S){'use strict';f.module("ngAnimate",["ng"]).directive("ngAnimateChildren",function(){return function(T,B,k){k=k.ngAnimateChildren;f.isString(k)&&0===k.length?B.data("$$ngAnimateChildren",!0):T.$watch(k,function(f){B.data("$$ngAnimateChildren",!!f)})}}).factory("$$animateReflow",["$$rAF","$document",function(f,B){return function(k){return f(function(){k()})}}]).config(["$provide","$animateProvider",function(T,B){function k(f){for(var g=0;g=A&&d>=x&&c()}var m=k(d);a=d.data("$$ngAnimateCSS3Data");if(-1!=m.getAttribute("class").indexOf(b)&&a){var q="",r="";g(b.split(" "),function(a,d){var b=(0=c;e--)d.end&&d.end(f[e]);f.length=c}}"string"!==typeof a&&(a=null===a||"undefined"===typeof a?"":""+a);var b,m,f=[],n=a,h;for(f.last=function(){return f[f.length-1]};a;){h="";m=!0;if(f.last()&&y[f.last()])a=a.replace(new RegExp("(.*)<\\s*\\/\\s*"+f.last()+"[^>]*>","i"),function(a,b){b=b.replace(I,"$1").replace(J,"$1");d.chars&&d.chars(s(b));return""}),e("",f.last());else{if(0===a.indexOf("\x3c!--"))b=a.indexOf("--",4),0<=b&&a.lastIndexOf("--\x3e",b)===b&&(d.comment&&d.comment(a.substring(4,
8 | b)),a=a.substring(b+3),m=!1);else if(z.test(a)){if(b=a.match(z))a=a.replace(b[0],""),m=!1}else if(K.test(a)){if(b=a.match(A))a=a.substring(b[0].length),b[0].replace(A,e),m=!1}else L.test(a)&&((b=a.match(B))?(b[4]&&(a=a.substring(b[0].length),b[0].replace(B,c)),m=!1):(h+="<",a=a.substring(1)));m&&(b=a.indexOf("<"),h+=0>b?a:a.substring(0,b),a=0>b?"":a.substring(b),d.chars&&d.chars(s(h)))}if(a==n)throw M("badparse",a);n=a}e()}function s(a){if(!a)return"";var d=N.exec(a);a=d[1];var c=d[3];if(d=d[2])r.innerHTML=
9 | d.replace(//g,">")}function t(a,d){var c=!1,e=g.bind(a,a.push);return{start:function(a,m,f){a=g.lowercase(a);!c&&y[a]&&(c=a);c||!0!==D[a]||(e("<"),e(a),g.forEach(m,function(c,f){var l=
10 | g.lowercase(f),m="img"===a&&"src"===l||"background"===l;!0!==Q[l]||!0===E[l]&&!d(c,m)||(e(" "),e(f),e('="'),e(C(c)),e('"'))}),e(f?"/>":">"))},end:function(a){a=g.lowercase(a);c||!0!==D[a]||(e(""),e(a),e(">"));a==c&&(c=!1)},chars:function(a){c||e(C(a))}}}var M=g.$$minErr("$sanitize"),B=/^<((?:[a-zA-Z])[\w:-]*)((?:\s+[\w:-]+(?:\s*=\s*(?:(?:"[^"]*")|(?:'[^']*')|[^>\s]+))?)*)\s*(\/?)\s*(>?)/,A=/^<\/\s*([\w:-]+)[^>]*>/,H=/([\w:-]+)(?:\s*=\s*(?:(?:"((?:[^"])*)")|(?:'((?:[^'])*)')|([^>\s]+)))?/g,L=/^,
11 | K=/^<\//,I=/\x3c!--(.*?)--\x3e/g,z=/]*?)>/i,J=/"]/,c=/^mailto:/;return function(e,b){function m(a){a&&l.push(F(a))}function f(a,
15 | c){l.push("');m(c);l.push("")}if(!e)return e;for(var n,h=e,l=[],k,p;n=h.match(d);)k=n[0],n[2]==n[3]&&(k="mailto:"+k),p=n.index,m(h.substr(0,p)),f(k,n[0].replace(c,"")),h=h.substring(p+n[0].length);m(h);return a(l.join(""))}}])})(window,window.angular);
16 | //# sourceMappingURL=angular-sanitize.min.js.map
17 |
--------------------------------------------------------------------------------
/data/example5/web/angular_1.3.1/angular-ui-router.min.js:
--------------------------------------------------------------------------------
1 | /**
2 | * State-based routing for AngularJS
3 | * @version v0.2.11
4 | * @link http://angular-ui.github.com/
5 | * @license MIT License, http://www.opensource.org/licenses/MIT
6 | */
7 | "undefined"!=typeof module&&"undefined"!=typeof exports&&module.exports===exports&&(module.exports="ui.router"),function(a,b,c){"use strict";function d(a,b){return J(new(J(function(){},{prototype:a})),b)}function e(a){return I(arguments,function(b){b!==a&&I(b,function(b,c){a.hasOwnProperty(c)||(a[c]=b)})}),a}function f(a,b){var c=[];for(var d in a.path){if(a.path[d]!==b.path[d])break;c.push(a.path[d])}return c}function g(a){if(Object.keys)return Object.keys(a);var c=[];return b.forEach(a,function(a,b){c.push(b)}),c}function h(a,b){if(Array.prototype.indexOf)return a.indexOf(b,Number(arguments[2])||0);var c=a.length>>>0,d=Number(arguments[2])||0;for(d=0>d?Math.ceil(d):Math.floor(d),0>d&&(d+=c);c>d;d++)if(d in a&&a[d]===b)return d;return-1}function i(a,b,c,d){var e,i=f(c,d),j={},k=[];for(var l in i)if(i[l].params&&(e=g(i[l].params),e.length))for(var m in e)h(k,e[m])>=0||(k.push(e[m]),j[e[m]]=a[e[m]]);return J({},j,b)}function j(a,b,c){if(!c){c=[];for(var d in a)c.push(d)}for(var e=0;e "));if(o[c]=d,F(a))m.push(c,[function(){return b.get(a)}],h);else{var e=b.annotate(a);I(e,function(a){a!==c&&g.hasOwnProperty(a)&&k(g[a],a)}),m.push(c,a,e)}n.pop(),o[c]=f}}function l(a){return G(a)&&a.then&&a.$$promises}if(!G(g))throw new Error("'invocables' must be an object");var m=[],n=[],o={};return I(g,k),g=n=o=null,function(d,f,g){function h(){--s||(t||e(r,f.$$values),p.$$values=r,p.$$promises=!0,delete p.$$inheritedValues,o.resolve(r))}function k(a){p.$$failure=a,o.reject(a)}function n(c,e,f){function i(a){l.reject(a),k(a)}function j(){if(!D(p.$$failure))try{l.resolve(b.invoke(e,g,r)),l.promise.then(function(a){r[c]=a,h()},i)}catch(a){i(a)}}var l=a.defer(),m=0;I(f,function(a){q.hasOwnProperty(a)&&!d.hasOwnProperty(a)&&(m++,q[a].then(function(b){r[a]=b,--m||j()},i))}),m||j(),q[c]=l.promise}if(l(d)&&g===c&&(g=f,f=d,d=null),d){if(!G(d))throw new Error("'locals' must be an object")}else d=i;if(f){if(!l(f))throw new Error("'parent' must be a promise returned by $resolve.resolve()")}else f=j;var o=a.defer(),p=o.promise,q=p.$$promises={},r=J({},d),s=1+m.length/3,t=!1;if(D(f.$$failure))return k(f.$$failure),p;f.$$inheritedValues&&e(r,f.$$inheritedValues),f.$$values?(t=e(r,f.$$values),p.$$inheritedValues=f.$$values,h()):(f.$$inheritedValues&&(p.$$inheritedValues=f.$$inheritedValues),J(q,f.$$promises),f.then(h,k));for(var u=0,v=m.length;v>u;u+=3)d.hasOwnProperty(m[u])?h():n(m[u],m[u+1],m[u+2]);return p}},this.resolve=function(a,b,c,d){return this.study(a)(b,c,d)}}function m(a,b,c){this.fromConfig=function(a,b,c){return D(a.template)?this.fromString(a.template,b):D(a.templateUrl)?this.fromUrl(a.templateUrl,b):D(a.templateProvider)?this.fromProvider(a.templateProvider,b,c):null},this.fromString=function(a,b){return E(a)?a(b):a},this.fromUrl=function(c,d){return E(c)&&(c=c(d)),null==c?null:a.get(c,{cache:b}).then(function(a){return a.data})},this.fromProvider=function(a,b,d){return c.invoke(a,null,d||{params:b})}}function n(a,d){function e(a){return D(a)?this.type.decode(a):p.$$getDefaultValue(this)}function f(b,c,d){if(!/^\w+(-+\w+)*$/.test(b))throw new Error("Invalid parameter name '"+b+"' in pattern '"+a+"'");if(n[b])throw new Error("Duplicate parameter name '"+b+"' in pattern '"+a+"'");n[b]=J({type:c||new o,$value:e},d)}function g(a,b,c){var d=a.replace(/[\\\[\]\^$*+?.()|{}]/g,"\\$&");if(!b)return d;var e=c?"?":"";return d+e+"("+b+")"+e}function h(a){if(!d.params||!d.params[a])return{};var b=d.params[a];return G(b)?b:{value:b}}d=b.isObject(d)?d:{};var i,j=/([:*])(\w+)|\{(\w+)(?:\:((?:[^{}\\]+|\\.|\{(?:[^{}\\]+|\\.)*\})+))?\}/g,k="^",l=0,m=this.segments=[],n=this.params={};this.source=a;for(var q,r,s,t,u;(i=j.exec(a))&&(q=i[2]||i[3],r=i[4]||("*"==i[1]?".*":"[^/]*"),s=a.substring(l,i.index),t=this.$types[r]||new o({pattern:new RegExp(r)}),u=h(q),!(s.indexOf("?")>=0));)k+=g(s,t.$subPattern(),D(u.value)),f(q,t,u),m.push(s),l=j.lastIndex;s=a.substring(l);var v=s.indexOf("?");if(v>=0){var w=this.sourceSearch=s.substring(v);s=s.substring(0,v),this.sourcePath=a.substring(0,l+v),I(w.substring(1).split(/[&?]/),function(a){f(a,null,h(a))})}else this.sourcePath=a,this.sourceSearch="";k+=g(s)+(d.strict===!1?"/?":"")+"$",m.push(s),this.regexp=new RegExp(k,d.caseInsensitive?"i":c),this.prefix=m[0]}function o(a){J(this,a)}function p(){function a(){return{strict:f,caseInsensitive:e}}function b(a){return E(a)||H(a)&&E(a[a.length-1])}function c(){I(h,function(a){if(n.prototype.$types[a.name])throw new Error("A type named '"+a.name+"' has already been defined.");var c=new o(b(a.def)?d.invoke(a.def):a.def);n.prototype.$types[a.name]=c})}var d,e=!1,f=!0,g=!0,h=[],i={"int":{decode:function(a){return parseInt(a,10)},is:function(a){return D(a)?this.decode(a.toString())===a:!1},pattern:/\d+/},bool:{encode:function(a){return a?1:0},decode:function(a){return 0===parseInt(a,10)?!1:!0},is:function(a){return a===!0||a===!1},pattern:/0|1/},string:{pattern:/[^\/]*/},date:{equals:function(a,b){return a.toISOString()===b.toISOString()},decode:function(a){return new Date(a)},encode:function(a){return[a.getFullYear(),("0"+(a.getMonth()+1)).slice(-2),("0"+a.getDate()).slice(-2)].join("-")},pattern:/[0-9]{4}-(?:0[1-9]|1[0-2])-(?:0[1-9]|[1-2][0-9]|3[0-1])/}};p.$$getDefaultValue=function(a){if(!b(a.value))return a.value;if(!d)throw new Error("Injectable functions cannot be called at configuration time");return d.invoke(a.value)},this.caseInsensitive=function(a){e=a},this.strictMode=function(a){f=a},this.compile=function(b,c){return new n(b,J(a(),c))},this.isMatcher=function(a){if(!G(a))return!1;var b=!0;return I(n.prototype,function(c,d){E(c)&&(b=b&&D(a[d])&&E(a[d]))}),b},this.type=function(a,b){return D(b)?(h.push({name:a,def:b}),g||c(),this):n.prototype.$types[a]},this.$get=["$injector",function(a){return d=a,g=!1,n.prototype.$types={},c(),I(i,function(a,b){n.prototype.$types[b]||(n.prototype.$types[b]=new o(a))}),this}]}function q(a,b){function d(a){var b=/^\^((?:\\[^a-zA-Z0-9]|[^\\\[\]\^$*+?.()|{}]+)*)/.exec(a.source);return null!=b?b[1].replace(/\\(.)/g,"$1"):""}function e(a,b){return a.replace(/\$(\$|\d{1,2})/,function(a,c){return b["$"===c?0:Number(c)]})}function f(a,b,c){if(!c)return!1;var d=a.invoke(b,b,{$match:c});return D(d)?d:!0}function g(b,c,d,e){function f(a,b,c){return"/"===m?a:b?m.slice(0,-1)+a:c?m.slice(1)+a:a}function g(a){function c(a){var c=a(d,b);return c?(F(c)&&b.replace().url(c),!0):!1}if(!a||!a.defaultPrevented){var e,f=i.length;for(e=0;f>e;e++)if(c(i[e]))return;j&&c(j)}}function l(){return h=h||c.$on("$locationChangeSuccess",g)}var m=e.baseHref(),n=b.url();return k||l(),{sync:function(){g()},listen:function(){return l()},update:function(a){return a?void(n=b.url()):void(b.url()!==n&&(b.url(n),b.replace()))},push:function(a,c,d){b.url(a.format(c||{})),d&&d.replace&&b.replace()},href:function(c,d,e){if(!c.validates(d))return null;var g=a.html5Mode(),h=c.format(d);if(e=e||{},g||null===h||(h="#"+a.hashPrefix()+h),h=f(h,g,e.absolute),!e.absolute||!h)return h;var i=!g&&h?"/":"",j=b.port();return j=80===j||443===j?"":":"+j,[b.protocol(),"://",b.host(),j,i,h].join("")}}}var h,i=[],j=null,k=!1;this.rule=function(a){if(!E(a))throw new Error("'rule' must be a function");return i.push(a),this},this.otherwise=function(a){if(F(a)){var b=a;a=function(){return b}}else if(!E(a))throw new Error("'rule' must be a function");return j=a,this},this.when=function(a,c){var g,h=F(c);if(F(a)&&(a=b.compile(a)),!h&&!E(c)&&!H(c))throw new Error("invalid 'handler' in when()");var i={matcher:function(a,c){return h&&(g=b.compile(c),c=["$match",function(a){return g.format(a)}]),J(function(b,d){return f(b,c,a.exec(d.path(),d.search()))},{prefix:F(a.prefix)?a.prefix:""})},regex:function(a,b){if(a.global||a.sticky)throw new Error("when() RegExp must not be global or sticky");return h&&(g=b,b=["$match",function(a){return e(g,a)}]),J(function(c,d){return f(c,b,a.exec(d.path()))},{prefix:d(a)})}},j={matcher:b.isMatcher(a),regex:a instanceof RegExp};for(var k in j)if(j[k])return this.rule(i[k](a,c));throw new Error("invalid 'what' in when()")},this.deferIntercept=function(a){a===c&&(a=!0),k=a},this.$get=g,g.$inject=["$location","$rootScope","$injector","$browser"]}function r(a,e){function f(a){return 0===a.indexOf(".")||0===a.indexOf("^")}function h(a,b){if(!a)return c;var d=F(a),e=d?a:a.name,g=f(e);if(g){if(!b)throw new Error("No reference point given for path '"+e+"'");for(var h=e.split("."),i=0,j=h.length,k=b;j>i;i++)if(""!==h[i]||0!==i){if("^"!==h[i])break;if(!k.parent)throw new Error("Path '"+e+"' not valid for state '"+b.name+"'");k=k.parent}else k=b;h=h.slice(i).join("."),e=k.name+(k.name&&h?".":"")+h}var l=v[e];return!l||!d&&(d||l!==a&&l.self!==a)?c:l}function l(a,b){w[a]||(w[a]=[]),w[a].push(b)}function m(b){b=d(b,{self:b,resolve:b.resolve||{},toString:function(){return this.name}});var c=b.name;if(!F(c)||c.indexOf("@")>=0)throw new Error("State must have a valid name");if(v.hasOwnProperty(c))throw new Error("State '"+c+"'' is already defined");var e=-1!==c.indexOf(".")?c.substring(0,c.lastIndexOf(".")):F(b.parent)?b.parent:"";if(e&&!v[e])return l(e,b.self);for(var f in y)E(y[f])&&(b[f]=y[f](b,y.$delegates[f]));if(v[c]=b,!b[x]&&b.url&&a.when(b.url,["$match","$stateParams",function(a,c){u.$current.navigable==b&&j(a,c)||u.transitionTo(b,a,{location:!1})}]),w[c])for(var g=0;g-1}function o(a){var b=a.split("."),c=u.$current.name.split(".");if("**"===b[0]&&(c=c.slice(c.indexOf(b[1])),c.unshift("**")),"**"===b[b.length-1]&&(c.splice(c.indexOf(b[b.length-2])+1,Number.MAX_VALUE),c.push("**")),b.length!=c.length)return!1;for(var d=0,e=b.length;e>d;d++)"*"===b[d]&&(c[d]="*");return c.join("")===b.join("")}function p(a,b){return F(a)&&!D(b)?y[a]:E(b)&&F(a)?(y[a]&&!y.$delegates[a]&&(y.$delegates[a]=y[a]),y[a]=b,this):this}function q(a,b){return G(a)?b=a:b.name=a,m(b),this}function r(a,e,f,l,m,p,q){function r(b,c,d,f){var g=a.$broadcast("$stateNotFound",b,c,d);if(g.defaultPrevented)return q.update(),A;if(!g.retry)return null;if(f.$retry)return q.update(),B;var h=u.transition=e.when(g.retry);return h.then(function(){return h!==u.transition?y:(b.options.$retry=!0,u.transitionTo(b.to,b.toParams,b.options))},function(){return A}),q.update(),h}function w(a,c,d,h,i){var j=d?c:k(g(a.params),c),n={$stateParams:j};i.resolve=m.resolve(a.resolve,n,i.resolve,a);var o=[i.resolve.then(function(a){i.globals=a})];return h&&o.push(h),I(a.views,function(c,d){var e=c.resolve&&c.resolve!==a.resolve?c.resolve:{};e.$template=[function(){return f.load(d,{view:c,locals:n,params:j})||""}],o.push(m.resolve(e,n,i.resolve,a).then(function(f){if(E(c.controllerProvider)||H(c.controllerProvider)){var g=b.extend({},e,n);f.$$controller=l.invoke(c.controllerProvider,null,g)}else f.$$controller=c.controller;f.$$state=a,f.$$controllerAs=c.controllerAs,i[d]=f}))}),e.all(o).then(function(){return i})}var y=e.reject(new Error("transition superseded")),z=e.reject(new Error("transition prevented")),A=e.reject(new Error("transition aborted")),B=e.reject(new Error("transition failed"));return t.locals={resolve:null,globals:{$stateParams:{}}},u={params:{},current:t.self,$current:t,transition:null},u.reload=function(){u.transitionTo(u.current,p,{reload:!0,inherit:!1,notify:!1})},u.go=function(a,b,c){return u.transitionTo(a,b,J({inherit:!0,relative:u.$current},c))},u.transitionTo=function(b,c,f){c=c||{},f=J({location:!0,inherit:!1,relative:null,notify:!0,reload:!1,$retry:!1},f||{});var m,n=u.$current,o=u.params,v=n.path,A=h(b,f.relative);if(!D(A)){var B={to:b,toParams:c,options:f},C=r(B,n.self,o,f);if(C)return C;if(b=B.to,c=B.toParams,f=B.options,A=h(b,f.relative),!D(A)){if(!f.relative)throw new Error("No such state '"+b+"'");throw new Error("Could not resolve '"+b+"' from state '"+f.relative+"'")}}if(A[x])throw new Error("Cannot transition to abstract state '"+b+"'");f.inherit&&(c=i(p,c||{},u.$current,A)),b=A;var E=b.path,F=0,G=E[F],H=t.locals,I=[];if(!f.reload)for(;G&&G===v[F]&&j(c,o,G.ownParams);)H=I[F]=G.locals,F++,G=E[F];if(s(b,n,H,f))return b.self.reloadOnSearch!==!1&&q.update(),u.transition=null,e.when(u.current);if(c=k(g(b.params),c||{}),f.notify&&a.$broadcast("$stateChangeStart",b.self,c,n.self,o).defaultPrevented)return q.update(),z;for(var L=e.when(H),M=F;M=F;d--)g=v[d],g.self.onExit&&l.invoke(g.self.onExit,g.self,g.locals.globals),g.locals=null;for(d=F;d=0?c:c+"@"+(b?b.state.name:"")}function x(a,b){var c,d=a.match(/^\s*({[^}]*})\s*$/);if(d&&(a=b+"("+d[1]+")"),c=a.replace(/\n/g," ").match(/^([^(]+?)\s*(\((.*)\))?$/),!c||4!==c.length)throw new Error("Invalid state ref '"+a+"'");return{state:c[1],paramExpr:c[3]||null}}function y(a){var b=a.parent().inheritedData("$uiView");return b&&b.state&&b.state.name?b.state:void 0}function z(a,c){var d=["location","inherit","reload"];return{restrict:"A",require:["?^uiSrefActive","?^uiSrefActiveEq"],link:function(e,f,g,h){var i=x(g.uiSref,a.current.name),j=null,k=y(f)||a.$current,l="FORM"===f[0].nodeName,m=l?"action":"href",n=!0,o={relative:k,inherit:!0},p=e.$eval(g.uiSrefOpts)||{};b.forEach(d,function(a){a in p&&(o[a]=p[a])});var q=function(b){if(b&&(j=b),n){var c=a.href(i.state,j,o),d=h[1]||h[0];return d&&d.$$setStateInfo(i.state,j),null===c?(n=!1,!1):void(f[0][m]=c)}};i.paramExpr&&(e.$watch(i.paramExpr,function(a){a!==j&&q(a)},!0),j=e.$eval(i.paramExpr)),q(),l||f.bind("click",function(b){var d=b.which||b.button;if(!(d>1||b.ctrlKey||b.metaKey||b.shiftKey||f.attr("target"))){var e=c(function(){a.go(i.state,j,o)});b.preventDefault(),b.preventDefault=function(){c.cancel(e)}}})}}}function A(a,b,c){return{restrict:"A",controller:["$scope","$element","$attrs",function(d,e,f){function g(){h()?e.addClass(m):e.removeClass(m)}function h(){return"undefined"!=typeof f.uiSrefActiveEq?a.$current.self===k&&i():a.includes(k.name)&&i()}function i(){return!l||j(l,b)}var k,l,m;m=c(f.uiSrefActiveEq||f.uiSrefActive||"",!1)(d),this.$$setStateInfo=function(b,c){k=a.get(b,y(e)),l=c,g()},d.$on("$stateChangeSuccess",g)}]}}function B(a){return function(b){return a.is(b)}}function C(a){return function(b){return a.includes(b)}}var D=b.isDefined,E=b.isFunction,F=b.isString,G=b.isObject,H=b.isArray,I=b.forEach,J=b.extend,K=b.copy;b.module("ui.router.util",["ng"]),b.module("ui.router.router",["ui.router.util"]),b.module("ui.router.state",["ui.router.router","ui.router.util"]),b.module("ui.router",["ui.router.state"]),b.module("ui.router.compat",["ui.router"]),l.$inject=["$q","$injector"],b.module("ui.router.util").service("$resolve",l),m.$inject=["$http","$templateCache","$injector"],b.module("ui.router.util").service("$templateFactory",m),n.prototype.concat=function(a,b){return new n(this.sourcePath+a+this.sourceSearch,b)},n.prototype.toString=function(){return this.source},n.prototype.exec=function(a,b){var c=this.regexp.exec(a);if(!c)return null;b=b||{};var d,e,f,g=this.parameters(),h=g.length,i=this.segments.length-1,j={};if(i!==c.length-1)throw new Error("Unbalanced capture group in route '"+this.source+"'");for(d=0;i>d;d++)f=g[d],e=this.params[f],j[f]=e.$value(c[d+1]);for(;h>d;d++)f=g[d],e=this.params[f],j[f]=e.$value(b[f]);return j},n.prototype.parameters=function(a){return D(a)?this.params[a]||null:g(this.params)},n.prototype.validates=function(a){var b,c,d=!0,e=this;return I(a,function(a,f){e.params[f]&&(c=e.params[f],b=!a&&D(c.value),d=d&&(b||c.type.is(a)))}),d},n.prototype.format=function(a){var b=this.segments,c=this.parameters();if(!a)return b.join("").replace("//","/");var d,e,f,g,h,i,j=b.length-1,k=c.length,l=b[0];if(!this.validates(a))return null;for(d=0;j>d;d++)g=c[d],f=a[g],h=this.params[g],(D(f)||"/"!==b[d]&&"/"!==b[d+1])&&(null!=f&&(l+=encodeURIComponent(h.type.encode(f))),l+=b[d+1]);for(;k>d;d++)g=c[d],f=a[g],null!=f&&(i=H(f),i&&(f=f.map(encodeURIComponent).join("&"+g+"=")),l+=(e?"&":"?")+g+"="+(i?f:encodeURIComponent(f)),e=!0);return l},n.prototype.$types={},o.prototype.is=function(){return!0},o.prototype.encode=function(a){return a},o.prototype.decode=function(a){return a},o.prototype.equals=function(a,b){return a==b},o.prototype.$subPattern=function(){var a=this.pattern.toString();return a.substr(1,a.length-2)},o.prototype.pattern=/.*/,b.module("ui.router.util").provider("$urlMatcherFactory",p),q.$inject=["$locationProvider","$urlMatcherFactoryProvider"],b.module("ui.router.router").provider("$urlRouter",q),r.$inject=["$urlRouterProvider","$urlMatcherFactoryProvider"],b.module("ui.router.state").value("$stateParams",{}).provider("$state",r),s.$inject=[],b.module("ui.router.state").provider("$view",s),b.module("ui.router.state").provider("$uiViewScroll",t),u.$inject=["$state","$injector","$uiViewScroll"],v.$inject=["$compile","$controller","$state"],b.module("ui.router.state").directive("uiView",u),b.module("ui.router.state").directive("uiView",v),z.$inject=["$state","$timeout"],A.$inject=["$state","$stateParams","$interpolate"],b.module("ui.router.state").directive("uiSref",z).directive("uiSrefActive",A).directive("uiSrefActiveEq",A),B.$inject=["$state"],C.$inject=["$state"],b.module("ui.router.state").filter("isState",B).filter("includedByState",C)}(window,window.angular);
--------------------------------------------------------------------------------
/data/example5/web/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/quanla/classreloading/efafff7686187a4b7d052bc3de0c878ad508e931/data/example5/web/favicon.ico
--------------------------------------------------------------------------------
/data/example5/web/fonts/FontAwesome.otf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/quanla/classreloading/efafff7686187a4b7d052bc3de0c878ad508e931/data/example5/web/fonts/FontAwesome.otf
--------------------------------------------------------------------------------
/data/example5/web/fonts/fontawesome-webfont.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/quanla/classreloading/efafff7686187a4b7d052bc3de0c878ad508e931/data/example5/web/fonts/fontawesome-webfont.eot
--------------------------------------------------------------------------------
/data/example5/web/fonts/fontawesome-webfont.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/quanla/classreloading/efafff7686187a4b7d052bc3de0c878ad508e931/data/example5/web/fonts/fontawesome-webfont.ttf
--------------------------------------------------------------------------------
/data/example5/web/fonts/fontawesome-webfont.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/quanla/classreloading/efafff7686187a4b7d052bc3de0c878ad508e931/data/example5/web/fonts/fontawesome-webfont.woff
--------------------------------------------------------------------------------
/data/example5/web/fonts/glyphicons-halflings-regular.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/quanla/classreloading/efafff7686187a4b7d052bc3de0c878ad508e931/data/example5/web/fonts/glyphicons-halflings-regular.eot
--------------------------------------------------------------------------------
/data/example5/web/fonts/glyphicons-halflings-regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/quanla/classreloading/efafff7686187a4b7d052bc3de0c878ad508e931/data/example5/web/fonts/glyphicons-halflings-regular.ttf
--------------------------------------------------------------------------------
/data/example5/web/fonts/glyphicons-halflings-regular.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/quanla/classreloading/efafff7686187a4b7d052bc3de0c878ad508e931/data/example5/web/fonts/glyphicons-halflings-regular.woff
--------------------------------------------------------------------------------
/data/example5/web/spa/app.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | (function() {
4 | /* App Module */
5 | angular.module("classreloading.app", [
6 | 'ui.router',
7 | 'ui.bootstrap',
8 | 'classreloading.hello'
9 | ])
10 |
11 | .run(function ($rootScope, $state, $stateParams) {
12 | // It's very handy to add references to $state and $stateParams to the $rootScope
13 | // so that you can access them from any scope within your applications.For example,
14 | // will set the
15 | // to active whenever 'contacts.list' or one of its decendents is active.
16 | $rootScope.$state = $state;
17 | $rootScope.$stateParams = $stateParams;
18 |
19 | $rootScope.$on('$stateChangeSuccess', function(event, toState, toParams, fromState, fromParams){
20 | window.scrollTo(0, 0);
21 | })
22 | })
23 |
24 | .config(function ($stateProvider, $urlRouterProvider) {
25 | $urlRouterProvider
26 | // If the url is ever invalid, e.g. '/asdf', then redirect to '/' aka the home state
27 | .otherwise("/hello");
28 | })
29 |
30 | .config(function ($locationProvider) {
31 | $locationProvider.html5Mode(false).hashPrefix("!");
32 | })
33 |
34 | ;
35 | })();
36 |
--------------------------------------------------------------------------------
/data/example5/web/spa/hello/AddContactModal.jade:
--------------------------------------------------------------------------------
1 | .modal-header
2 | h3.modal-title Add a new contact
3 | .modal-body
4 | form(name="form")
5 | .form-group
6 | label.control-label Contact name
7 | input.form-control(ng-model="contact.name",required,autofocus)
8 | .form-group
9 | label.control-label Phone No
10 | input.form-control(ng-model="contact.phone",required)
11 | .modal-footer
12 | button.btn.btn-default(ng-click="add()",ng-disabled="form.$invalid",style="min-width: 150px") Add
13 |
--------------------------------------------------------------------------------
/data/example5/web/spa/hello/Hello.jade:
--------------------------------------------------------------------------------
1 | h1 Hello World
2 |
3 | .lead Here are contacts that we have in database:
4 |
5 | table.table.table-striped.table-hover
6 | thead
7 | tr
8 | th(style="width: 15px") #
9 | th Name
10 | th Phone
11 | th
12 |
13 | tbody
14 | tr(ng-if="!contacts.length")
15 | td.text-center.text-muted(colspan="4") No record(s)
16 | tr(ng-repeat="contact in contacts")
17 | td.text-right(style="width: 20px") {{ $index + 1 }}
18 | td {{ contact.name }}
19 | td {{ contact.phone }}
20 | td.text-right
21 | a.text-danger(href="",ng-click="remove(contact)")
22 | span.glyphicon.glyphicon-remove
23 |
24 | button.btn.btn-success(ng-click="showAddForm()")
25 | span.glyphicon.glyphicon-plus
26 | | Add new contact
--------------------------------------------------------------------------------
/data/example5/web/spa/hello/Hello.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | (function() {
4 |
5 | angular.module('classreloading.hello', [
6 | ])
7 |
8 | .config(function ($stateProvider) {
9 |
10 | $stateProvider
11 | .state('hello', {
12 | url: '/hello',
13 | templateUrl: "/hello/Hello.jade?v=" + App.version,
14 | controller: "classreloading.hello.Ctrl"
15 | })
16 | ;
17 | })
18 |
19 | .controller("classreloading.hello.Ctrl", function($scope, $modal, ContactService) {
20 | ContactService.getAll().success(function(contacts) {
21 | $scope.contacts = contacts;
22 | });
23 |
24 | $scope.showAddForm = function() {
25 | $modal.open({
26 | templateUrl: "/hello/AddContactModal.jade",
27 | controller: "classreloading.hello.AddContactModalCtrl"
28 | })
29 | .result.then(function(contact) {
30 | $scope.contacts.push(contact);
31 | });
32 | };
33 |
34 | $scope.remove = function(contact) {
35 | if (!confirm("Remove this contact: " + contact.name + " - " + contact.phone + "?")) {
36 | return;
37 | }
38 |
39 | ContactService.remove(contact).success(function() {
40 | $scope.contacts.splice($scope.contacts.indexOf(contact), 1);
41 | });
42 | };
43 |
44 | })
45 |
46 | .controller("classreloading.hello.AddContactModalCtrl", function($scope, ContactService, $modalInstance) {
47 | $scope.contact = {};
48 | $scope.add = function() {
49 | ContactService.add($scope.contact).success(function(contact1) {
50 | $modalInstance.close(contact1);
51 | });
52 | };
53 | })
54 |
55 |
56 | .factory('ContactService', function ($http) {
57 | return {
58 | getAll : function() {
59 | return $http.post("/contact?action=getAll", 0);
60 | },
61 | add : function(contact) {
62 | return $http.post("/contact?action=add", contact);
63 | },
64 | remove : function(contact) {
65 | return $http.post("/contact?action=remove&id=" + contact.id, contact);
66 | }
67 | };
68 | })
69 | ;
70 |
71 | })();
--------------------------------------------------------------------------------
/data/example5/web/spa/spa.jade:
--------------------------------------------------------------------------------
1 | !!!
2 | html(ng-app="classreloading.app",lang="en")
3 | head
4 | title Little Phone Book
5 | meta(name="viewport",content="width=device-width, initial-scale=1")
6 |
7 | meta(charset="UTF-8")
8 | link(rel="stylesheet",href="/bootstrap_3.2.0/bootstrap.min.css")
9 |
10 | script(src="/jquery-2.1.1/jquery-2.1.1.min.js")
11 | script(src="/bootstrap_3.2.0/bootstrap.min.js")
12 |
13 | script(src="/angular_1.3.1/angular.min.js")
14 | script(src="/angular_1.3.1/angular-resource.min.js")
15 | script(src="/angular_1.3.1/angular-sanitize.min.js")
16 | script(src="/angular_1.3.1/angular-animate.min.js")
17 |
18 | script(src="/angular_1.3.1/angular-ui-router.min.js")
19 |
20 | script(src="/bootstrap_3.2.0/ui-bootstrap-tpls-0.11.2.min.js")
21 |
22 | // spa-js
23 |
24 | script
25 | var App = App || {};
26 | App.version = "#{version}";
27 |
28 | body
29 | .container(ui-view)
30 | //
31 | pre
32 | div $state = {{$state.current.name}}
33 | div $stateParams = {{$stateParams}}
34 | div $state full url = {{ $state.$current.url.source }}
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 4.0.0
4 | qj.blog
5 | classreloading
6 | 1.0-SNAPSHOT
7 |
8 |
9 |
10 | org.apache.maven.plugins
11 | maven-compiler-plugin
12 | 3.2
13 |
14 | 1.8
15 | 1.8
16 |
17 |
18 |
19 |
20 |
21 |
22 | de.neuland-bfi
23 | jade4j
24 | 0.4.0
25 |
26 |
27 | javax
28 | javaee-api
29 | 7.0
30 |
31 |
32 | org.eclipse.jetty
33 | jetty-server
34 | 9.2.2.v20140723
35 |
36 |
37 | org.eclipse.jetty
38 | jetty-servlet
39 | 9.2.2.v20140723
40 |
41 |
42 | org.eclipse.jetty
43 | jetty-webapp
44 | 9.2.2.v20140723
45 | test
46 |
47 |
48 | org.xerial
49 | sqlite-jdbc
50 | 3.8.7
51 |
52 |
53 |
54 | com.google.code.gson
55 | gson
56 | 2.3
57 |
58 |
59 |
60 |
61 |
62 |
--------------------------------------------------------------------------------
/push_github.cmd:
--------------------------------------------------------------------------------
1 | git push origin master
--------------------------------------------------------------------------------
/run_example1.bat:
--------------------------------------------------------------------------------
1 | mvn exec:java -Dexec.mainClass="qj.blog.classreloading.example1.StaticInt"
--------------------------------------------------------------------------------
/run_example2.bat:
--------------------------------------------------------------------------------
1 | mvn exec:java -Dexec.mainClass="qj.blog.classreloading.example2.ReloadingContinuously"
--------------------------------------------------------------------------------
/run_example3.bat:
--------------------------------------------------------------------------------
1 | mvn exec:java -Dexec.mainClass="qj.blog.classreloading.example3.ContextReloading"
--------------------------------------------------------------------------------
/run_example4.bat:
--------------------------------------------------------------------------------
1 | mvn exec:java -Dexec.mainClass="qj.blog.classreloading.example4.KeepConnectionPool"
--------------------------------------------------------------------------------
/run_example5.bat:
--------------------------------------------------------------------------------
1 | mvn exec:java -Dexec.mainClass="qj.blog.classreloading.example5.LittlePhoneBookMain"
--------------------------------------------------------------------------------
/src/main/ai/1_2_loaders.ai:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/quanla/classreloading/efafff7686187a4b7d052bc3de0c878ad508e931/src/main/ai/1_2_loaders.ai
--------------------------------------------------------------------------------
/src/main/ai/2_many_loaders.ai:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/quanla/classreloading/efafff7686187a4b7d052bc3de0c878ad508e931/src/main/ai/2_many_loaders.ai
--------------------------------------------------------------------------------
/src/main/ai/3_context_reloading.ai:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/quanla/classreloading/efafff7686187a4b7d052bc3de0c878ad508e931/src/main/ai/3_context_reloading.ai
--------------------------------------------------------------------------------
/src/main/ai/4_persisting_connection.ai:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/quanla/classreloading/efafff7686187a4b7d052bc3de0c878ad508e931/src/main/ai/4_persisting_connection.ai
--------------------------------------------------------------------------------
/src/main/ai/5_reloading_web_context.ai:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/quanla/classreloading/efafff7686187a4b7d052bc3de0c878ad508e931/src/main/ai/5_reloading_web_context.ai
--------------------------------------------------------------------------------
/src/main/ai/5_web_app.ai:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/quanla/classreloading/efafff7686187a4b7d052bc3de0c878ad508e931/src/main/ai/5_web_app.ai
--------------------------------------------------------------------------------
/src/main/java/qj/blog/classreloading/example1/StaticInt.java:
--------------------------------------------------------------------------------
1 | package qj.blog.classreloading.example1;
2 |
3 | import static java.lang.System.*;
4 |
5 | import qj.util.ReflectUtil;
6 | import qj.util.lang.DynamicClassLoader;
7 |
8 | /**
9 | * Created by Quan on 26/10/2014.
10 | */
11 | public class StaticInt {
12 | public static void main(String[] args) {
13 | Class> userClass1 = User.class;
14 | Class> userClass2 = new DynamicClassLoader("target/classes")
15 | .load("qj.blog.classreloading.example1.StaticInt$User");
16 |
17 | out.println("Seems to be the same class:");
18 | out.println(userClass1.getName());
19 | out.println(userClass2.getName());
20 | out.println();
21 |
22 | out.println("But why there are 2 different class loaders:");
23 | out.println(userClass1.getClassLoader());
24 | out.println(userClass2.getClassLoader());
25 | out.println();
26 |
27 | User.age = 11;
28 | out.println("And different age values:");
29 | out.println((int) ReflectUtil.getStaticFieldValue("age", userClass1));
30 | out.println((int) ReflectUtil.getStaticFieldValue("age", userClass2));
31 | }
32 |
33 | public static class User {
34 | public static int age = 10;
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/src/main/java/qj/blog/classreloading/example2/ReloadingContinuously.java:
--------------------------------------------------------------------------------
1 | package qj.blog.classreloading.example2;
2 |
3 | import qj.util.ReflectUtil;
4 | import qj.util.ThreadUtil;
5 | import qj.util.lang.DynamicClassLoader;
6 |
7 | /**
8 | * Created by Quan on 31/10/2014.
9 | */
10 | public class ReloadingContinuously {
11 | public static void main(String[] args) {
12 | for (;;) {
13 | Class> userClass = new DynamicClassLoader("target/classes")
14 | .load("qj.blog.classreloading.example2.ReloadingContinuously$User");
15 | ReflectUtil.invokeStatic("hobby", userClass);
16 | ThreadUtil.sleep(2000);
17 | }
18 | }
19 |
20 | @SuppressWarnings("UnusedDeclaration")
21 | public static class User {
22 | public static void hobby() {
23 | playFootball(); // Will comment during runtime
24 | // playBasketball(); // Will uncomment during runtime
25 | }
26 |
27 | // Will comment during runtime
28 | public static void playFootball() {
29 | System.out.println("Play Football");
30 | }
31 |
32 | // Will uncomment during runtime
33 | // public static void playBasketball() {
34 | // System.out.println("Play Basketball");
35 | // }
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/src/main/java/qj/blog/classreloading/example3/ContextReloading.java:
--------------------------------------------------------------------------------
1 | package qj.blog.classreloading.example3;
2 |
3 | import static qj.util.ReflectUtil.*;
4 | import qj.util.ThreadUtil;
5 | import qj.util.lang.DynamicClassLoader;
6 |
7 | /**
8 | * Created by Quan on 31/10/2014.
9 | */
10 | public class ContextReloading {
11 | public static void main(String[] args) {
12 | for (;;) {
13 | Object context = createContext();
14 | invokeHobbyService(context);
15 | ThreadUtil.sleep(2000);
16 | }
17 | }
18 |
19 | private static Object createContext() {
20 | Class> contextClass = new DynamicClassLoader("target/classes")
21 | .load("qj.blog.classreloading.example3.ContextReloading$Context");
22 | Object context = newInstance(contextClass);
23 | invoke("init", context);
24 | return context;
25 | }
26 |
27 | private static void invokeHobbyService(Object context) {
28 | Object hobbyService = getFieldValue("hobbyService", context);
29 | invoke("hobby", hobbyService);
30 | }
31 |
32 | @SuppressWarnings("UnusedDeclaration")
33 | public static class Context {
34 | public HobbyService hobbyService = new HobbyService();
35 |
36 | public void init() {
37 | // Init your services here
38 | hobbyService.user = new User();
39 | }
40 | }
41 |
42 | public static class HobbyService {
43 |
44 | public User user;
45 |
46 | public void hobby() {
47 | user.hobby();
48 | }
49 | }
50 |
51 | public static class User {
52 | public static void hobby() {
53 | // playFootball(); // Will comment during runtime
54 | playBasketball(); // Will uncomment during runtime
55 | }
56 |
57 | // Will comment during runtime
58 | // public static void playFootball() {
59 | // System.out.println("Play Football");
60 | // }
61 |
62 | // Will uncomment during runtime
63 | public static void playBasketball() {
64 | System.out.println("Play Basketball");
65 | }
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/src/main/java/qj/blog/classreloading/example4/KeepConnectionPool.java:
--------------------------------------------------------------------------------
1 | package qj.blog.classreloading.example4;
2 |
3 | import static qj.util.ReflectUtil.*;
4 |
5 | import qj.blog.classreloading.example4.crossing.ConnectionPool;
6 | import qj.util.ThreadUtil;
7 | import qj.util.lang.ExceptingClassLoader;
8 |
9 | /**
10 | * Created by Quan on 01/11/2014.
11 | */
12 | public class KeepConnectionPool {
13 | public static void main(String[] args) {
14 |
15 | ConnectionPool pool = new ConnectionPool();
16 |
17 | for (;;) {
18 | Object context = createContext(pool);
19 |
20 | invokeService(context);
21 |
22 | ThreadUtil.sleep(2000);
23 | }
24 | }
25 |
26 | private static Object createContext(ConnectionPool pool) {
27 | ExceptingClassLoader classLoader = new ExceptingClassLoader(
28 | (className) -> className.contains(".crossing."),
29 | "target/classes");
30 | Class> contextClass = classLoader.load("qj.blog.classreloading.example4.reloadable.Context");
31 | Object context = newInstance(contextClass);
32 |
33 | setFieldValue(pool, "pool", context);
34 | invoke("init", context);
35 |
36 | return context;
37 | }
38 |
39 | private static void invokeService(Object context) {
40 | Object hobbyService = getFieldValue("userService", context);
41 | invoke("hello", hobbyService);
42 | }
43 |
44 |
45 |
46 | }
47 |
--------------------------------------------------------------------------------
/src/main/java/qj/blog/classreloading/example4/crossing/Connection.java:
--------------------------------------------------------------------------------
1 | package qj.blog.classreloading.example4.crossing;
2 |
3 | public class Connection {
4 | public String getUserName() {
5 | // System.out.println("Connection CL: " + this.getClass().getClassLoader()); // Will output DefaultClassLoader
6 | return "Joe";
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/src/main/java/qj/blog/classreloading/example4/crossing/ConnectionPool.java:
--------------------------------------------------------------------------------
1 | package qj.blog.classreloading.example4.crossing;
2 |
3 | public class ConnectionPool {
4 | Connection conn = new Connection();
5 |
6 | public Connection getConnection() {
7 | return conn;
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/src/main/java/qj/blog/classreloading/example4/reloadable/Context.java:
--------------------------------------------------------------------------------
1 | package qj.blog.classreloading.example4.reloadable;
2 |
3 | import qj.blog.classreloading.example4.crossing.ConnectionPool;
4 |
5 | @SuppressWarnings("UnusedDeclaration")
6 | public class Context {
7 | public ConnectionPool pool;
8 |
9 | public UserService userService = new UserService();
10 |
11 | public void init() {
12 | userService.pool = pool;
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/src/main/java/qj/blog/classreloading/example4/reloadable/UserService.java:
--------------------------------------------------------------------------------
1 | package qj.blog.classreloading.example4.reloadable;
2 |
3 | import qj.blog.classreloading.example4.crossing.ConnectionPool;
4 |
5 | public class UserService {
6 | ConnectionPool pool;
7 |
8 | @SuppressWarnings("UnusedDeclaration")
9 | public void hello() {
10 | // System.out.println("UserService CL: " + this.getClass().getClassLoader()); // Will output ExceptingClassLoader
11 | System.out.println("Hi " + pool.getConnection().getUserName());
12 | }
13 | }
--------------------------------------------------------------------------------
/src/main/java/qj/blog/classreloading/example5/LittlePhoneBookMain.java:
--------------------------------------------------------------------------------
1 | package qj.blog.classreloading.example5;
2 |
3 | import org.eclipse.jetty.server.Server;
4 | import org.eclipse.jetty.servlet.FilterHolder;
5 | import org.eclipse.jetty.servlet.ServletContextHandler;
6 | import org.eclipse.jetty.servlet.ServletHolder;
7 | import qj.tool.web.ReloadingWebContext;
8 | import qj.tool.web.ResourceFilter;
9 | import qj.util.PropertiesUtil;
10 | import qj.util.SystemUtil;
11 | import qj.util.ThreadUtil;
12 | import qj.util.funct.F0;
13 | import qj.util.funct.P0;
14 | import qj.util.lang.ExceptingClassLoader;
15 |
16 | import javax.servlet.DispatcherType;
17 | import javax.servlet.ServletException;
18 | import javax.servlet.http.HttpServlet;
19 | import javax.servlet.http.HttpServletRequest;
20 | import javax.servlet.http.HttpServletResponse;
21 | import java.io.IOException;
22 | import java.sql.Connection;
23 | import java.sql.DriverManager;
24 | import java.sql.SQLException;
25 | import java.sql.Statement;
26 | import java.util.EnumSet;
27 | import java.util.Properties;
28 |
29 | public class LittlePhoneBookMain {
30 | public static boolean development = true;
31 | public static String version = "1.0.0";
32 |
33 | public static void main(String[] args) throws Exception {
34 | Properties config = PropertiesUtil.loadPropertiesFromFile("data/example5/config.properties");
35 |
36 | startServer(config);
37 | }
38 |
39 | public static void startServer(Properties config) throws Exception {
40 | final ServerControl webServer = startWebServer(config);
41 |
42 | // Console commands are used to control server
43 | SystemUtil.onReturn(line -> {
44 | // Type exit then enter to stop the server
45 | if ("exit".equals(line)) {
46 | System.out.print("Stopping web server...");
47 | webServer.closeF.run();
48 | System.out.print(" done.");
49 | System.exit(0);
50 | }
51 | });
52 | }
53 |
54 | public static ServerControl startWebServer(Properties config) throws Exception {
55 | int port = Integer.parseInt(config.getProperty("web.port"));
56 |
57 | // Create the connection pool in the persisted area
58 | DbPool dbPool = initDatabase(config);
59 |
60 | ServletContextHandler servletContext = new ServletContextHandler(ServletContextHandler.SESSIONS);
61 | servletContext.setContextPath("/");
62 |
63 | ReloadingWebContext contextLoader = new ReloadingWebContext(
64 | "qj.blog.classreloading.example5.reloadable.Context",
65 | () -> ( development ?
66 | // During development, the dynamic class loader will be used
67 | new ExceptingClassLoader(
68 | (className) -> className.startsWith("qj.util"),
69 | "target/classes"
70 | ) :
71 |
72 | // During production, the default class loader will be used
73 | LittlePhoneBookMain.class.getClassLoader()
74 | ),
75 | development ?
76 | // During development, each time a GET to root URL "/", the dynamic context will be reloaded
77 | (req) -> req.getMethod().equalsIgnoreCase("GET") && req.getRequestURI().equals("/") :
78 | null
79 | );
80 |
81 | // Fields to be set each time the context is reloaded
82 | contextLoader.setField("development", development);
83 | contextLoader.setField("buildVersion", version);
84 | contextLoader.setField("connF", dbPool.connF);
85 |
86 | // Method "init" will be called with param "data/example5/web" each time the context is reloaded
87 | contextLoader.initWith("init", "data/example5/web");
88 |
89 | // Method "close" will be called each time context is un-linked ( to create and link to newer context, with
90 | // newer classes)
91 | contextLoader.beforeClose("close");
92 |
93 | // The "stubServlet" method will provide "stub" servlets which will retrieve real servlets in the reloaded
94 | // context each time a request is served
95 | servletContext.addServlet( new ServletHolder(contextLoader.stubServlet("jade")), "/");
96 |
97 | servletContext.addServlet( new ServletHolder(wrapServlet(contextLoader.stubServlet("contact"), dbPool.closeThreadConn)),
98 | "/contact");
99 |
100 | servletContext.addServlet( new ServletHolder(contextLoader.stubServlet("jade")), "*.jade");
101 |
102 | // Serve resources
103 | ResourceFilter resourceFilter = resourceFilter("data/example5/web");
104 | servletContext.addFilter(
105 | new FilterHolder(resourceFilter),
106 | "/*", EnumSet.of(DispatcherType.REQUEST));
107 |
108 | final Server server = new Server(port);
109 | server.setHandler(servletContext);
110 |
111 | server.start();
112 | System.out.println("Server started on port " + port);
113 |
114 | final Runnable closeF = () -> {
115 | System.out.print("Stopping box server...");
116 | try {
117 | server.stop();
118 | } catch (Exception e1) {
119 | e1.printStackTrace();
120 | }
121 | dbPool.closePool.e();
122 | System.out.print(" done.");
123 | };
124 | return new ServerControl(closeF);
125 | }
126 |
127 | private static DbPool initDatabase(Properties config) throws SQLException, ClassNotFoundException {
128 | DbPool dbPool = new DbPool(config);
129 | Connection connection = dbPool.connF.e();
130 | initDb(connection);
131 | dbPool.closeThreadConn.e();
132 | return dbPool;
133 | }
134 |
135 | public static ResourceFilter resourceFilter(String boxWebLoc) {
136 | return new ResourceFilter(
137 | req -> null,
138 | boxWebLoc
139 | );
140 | }
141 |
142 | public static class ServerControl {
143 | Runnable closeF;
144 |
145 | public ServerControl(Runnable closeF) {
146 | this.closeF = closeF;
147 | }
148 | }
149 |
150 | /**
151 | * This is pool provide only 1 shared connection to the SQLite memory database
152 | */
153 | static class DbPool {
154 |
155 | public F0 connF;
156 | public P0 closeThreadConn;
157 | protected P0 closePool;
158 |
159 | public DbPool(Properties config) throws SQLException, ClassNotFoundException {
160 |
161 | Class.forName(config.getProperty("db.driver"));
162 |
163 | Connection connection = DriverManager.getConnection(config.getProperty("db.url"));
164 |
165 | ThreadUtil.ThreadLocalCache threadLocal = ThreadUtil.threadLocalCache(() -> connection);
166 | connF = threadLocal.cacheF;
167 | closeThreadConn = () -> {
168 | // Connection conn = threadLocal.removeF.e();
169 | // if (conn != null) {
170 | //// System.out.println("Closing thread ds");
171 | // IOUtil.close(conn);
172 | // }
173 | };
174 |
175 | closePool = () -> {
176 | //noinspection EmptyCatchBlock
177 | try {
178 | connection.close();
179 | } catch (SQLException e1) {
180 | }
181 | };
182 | }
183 |
184 | }
185 |
186 | /**
187 | * The SQLite memory db is initialized before use
188 | * @throws SQLException
189 | */
190 | private static void initDb(Connection connection) throws SQLException {
191 | Statement statement = connection.createStatement();
192 | statement.setQueryTimeout(30); // set timeout to 30 sec.
193 |
194 | statement.executeUpdate("drop table if exists contact");
195 | statement.executeUpdate("create table contact (id integer PRIMARY KEY AUTOINCREMENT, name string, phone string)");
196 | statement.executeUpdate("insert into contact values(1, 'Andrew King', '0648 6815 1654')");
197 | statement.executeUpdate("insert into contact values(2, 'William Shakespeare', '0234 5234 3264')");
198 | }
199 |
200 | private static HttpServlet wrapServlet(HttpServlet servlet, P0 closeThreadConn) {
201 | return new HttpServlet() {
202 | protected void service(HttpServletRequest req,
203 | HttpServletResponse resp) throws ServletException,
204 | IOException {
205 | try {
206 | servlet.service(req, resp);
207 | } finally {
208 | closeThreadConn.e();
209 | }
210 | }
211 | };
212 | }
213 |
214 | // public static class Build {
215 | // public static void main(String[] args) {
216 | // System.out.println(BuildUtil.runCommand(LittlePhoneBookMain.class));
217 | // }
218 | // }
219 |
220 | }
221 |
--------------------------------------------------------------------------------
/src/main/java/qj/blog/classreloading/example5/reloadable/Context.java:
--------------------------------------------------------------------------------
1 | package qj.blog.classreloading.example5.reloadable;
2 |
3 | import qj.blog.classreloading.example5.reloadable.servlet.ContactServlet;
4 | import qj.blog.classreloading.example5.reloadable.servlet.JadeServlet;
5 | import qj.util.funct.F0;
6 |
7 | import java.sql.Connection;
8 |
9 | @SuppressWarnings("UnusedDeclaration")
10 | public class Context {
11 | public String buildVersion;
12 | public boolean development;
13 | public F0 connF;
14 |
15 | public JadeServlet jadeServlet = new JadeServlet();
16 | public ContactServlet contactServlet = new ContactServlet();
17 |
18 | public void init(String webLoc) {
19 | // System.out.println("Initializing context.");
20 |
21 | jadeServlet.version = buildVersion;
22 | jadeServlet.init(webLoc);
23 |
24 | contactServlet.connF = connF;
25 | }
26 |
27 | public void close() {
28 | // System.out.println("Closing context.");
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/src/main/java/qj/blog/classreloading/example5/reloadable/dao/ContactDAO.java:
--------------------------------------------------------------------------------
1 | package qj.blog.classreloading.example5.reloadable.dao;
2 |
3 | import qj.blog.classreloading.example5.reloadable.model.Contact;
4 | import qj.tool.sql.Builder;
5 | import qj.tool.sql.Template;
6 |
7 | import java.sql.Connection;
8 | import java.util.List;
9 |
10 | /**
11 | * Created by Quan on 22/12/2014.
12 | */
13 | public class ContactDAO {
14 | static Template template = new Builder<>(Contact.class)
15 | .build();
16 |
17 | public static List selectAll(Connection conn) {
18 | return template.selectAll(conn);
19 | }
20 |
21 | public static void insert(Contact contact, Connection conn) {
22 | template.insert(contact, conn);
23 | }
24 |
25 | public static void delete(Long id, Connection conn) {
26 | template.deleteById(id, conn);
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/src/main/java/qj/blog/classreloading/example5/reloadable/model/Contact.java:
--------------------------------------------------------------------------------
1 | package qj.blog.classreloading.example5.reloadable.model;
2 |
3 | /**
4 | * Created by Quan on 22/12/2014.
5 | */
6 | public class Contact {
7 | public Long id;
8 | public String name;
9 | public String phone;
10 | }
11 |
--------------------------------------------------------------------------------
/src/main/java/qj/blog/classreloading/example5/reloadable/servlet/ContactServlet.java:
--------------------------------------------------------------------------------
1 | package qj.blog.classreloading.example5.reloadable.servlet;
2 |
3 | import com.google.gson.Gson;
4 | import qj.blog.classreloading.example5.reloadable.dao.ContactDAO;
5 | import qj.blog.classreloading.example5.reloadable.model.Contact;
6 | import qj.util.funct.F0;
7 |
8 | import javax.servlet.ServletException;
9 | import javax.servlet.http.HttpServlet;
10 | import javax.servlet.http.HttpServletRequest;
11 | import javax.servlet.http.HttpServletResponse;
12 | import java.io.IOException;
13 | import java.sql.Connection;
14 |
15 | /**
16 | * Created by Quan on 22/12/2014.
17 | */
18 | public class ContactServlet extends HttpServlet {
19 |
20 | public F0 connF;
21 |
22 | @Override
23 | protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
24 | String action = req.getParameter("action");
25 |
26 | switch (action) {
27 | case "getAll":
28 | getAll(resp);
29 | break;
30 | case "add":
31 | add(req, resp);
32 | break;
33 | case "remove":
34 | remove(req, resp);
35 | break;
36 |
37 | }
38 | }
39 |
40 | private void getAll(HttpServletResponse resp) throws IOException {
41 | new Gson().toJson(ContactDAO.selectAll(connF.e()), resp.getWriter());
42 | }
43 |
44 | private void add(HttpServletRequest req, HttpServletResponse resp) throws IOException {
45 |
46 | Gson gson = new Gson();
47 | Contact contact = gson.fromJson(req.getReader(), Contact.class);
48 |
49 | ContactDAO.insert(contact, connF.e());
50 |
51 | gson.toJson(contact, resp.getWriter());
52 | }
53 |
54 | private void remove(HttpServletRequest req, HttpServletResponse resp) throws IOException {
55 | Long id = Long.valueOf(req.getParameter("id"));
56 |
57 | ContactDAO.delete(id, connF.e());
58 |
59 | resp.getWriter().write(0);
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/src/main/java/qj/blog/classreloading/example5/reloadable/servlet/JadeServlet.java:
--------------------------------------------------------------------------------
1 | package qj.blog.classreloading.example5.reloadable.servlet;
2 |
3 | import de.neuland.jade4j.Jade4J;
4 | import de.neuland.jade4j.model.JadeModel;
5 | import de.neuland.jade4j.template.JadeTemplate;
6 | import qj.util.Cols;
7 | import qj.util.FileUtil;
8 | import qj.util.StringUtil;
9 | import qj.util.funct.P2;
10 | import qj.util.math.Range;
11 |
12 | import javax.servlet.ServletException;
13 | import javax.servlet.http.HttpServlet;
14 | import javax.servlet.http.HttpServletRequest;
15 | import javax.servlet.http.HttpServletResponse;
16 | import java.io.File;
17 | import java.io.IOException;
18 | import java.io.StringWriter;
19 | import java.util.LinkedList;
20 |
21 | public class JadeServlet extends HttpServlet {
22 | public String version = null;
23 | private String webLoc;
24 |
25 | @Override
26 | public void doGet(HttpServletRequest req, HttpServletResponse resp)
27 | throws ServletException, IOException {
28 | resp.setContentType("text/html; charset=UTF-8");
29 |
30 | if (StringUtil.countHappens('.', req.getServerName()) == 1) {
31 | resp.sendRedirect("http://www." + req.getServerName()); // Fix ui-sref urls
32 | return;
33 | }
34 |
35 | String requestURI = req.getRequestURI();
36 | if (requestURI.equals("/")) {
37 | requestURI = "/spa.jade";
38 | }
39 | File file = new File(webLoc + "/spa" + requestURI);
40 |
41 | if (!file.exists()) {
42 | resp.sendRedirect("/#!" + requestURI.replaceFirst("/$", "")); // Fix ui-sref urls
43 | return;
44 | }
45 |
46 | JadeTemplate template = Jade4J.getTemplate(file.getPath());
47 | if ("/spa.jade".equals(requestURI)) {
48 | StringWriter buffer = new StringWriter();
49 | template.process(new JadeModel(Cols.map(
50 | "version", version
51 | )), buffer);
52 |
53 | String target = "";
54 |
55 | String scriptLocations = allJs();
56 |
57 | String content = buffer.toString();
58 | resp.getWriter().write(
59 | StringUtil.replace(scriptLocations, Range.fromlength(content.indexOf(target), target.length()), content)
60 | );
61 | } else {
62 | template.process(new JadeModel(null), resp.getWriter());
63 | }
64 | }
65 |
66 | private String allJs() {
67 | LinkedList col = new LinkedList<>();
68 | P2 collect = (file, path) -> {
69 | if (file.getName().endsWith(".js")) {
70 | if (StringUtil.isEmpty(path)) {
71 | col.add("/" + file.getName());
72 | } else {
73 | col.add("/" + path.replaceAll("\\\\", "/") + "/" + file.getName());
74 | }
75 | }
76 | };
77 | FileUtil.eachFile(new File(webLoc + "/spa"), collect);
78 |
79 | return Cols.join((Iterable)Cols.yield(col, s -> ""), "");
80 | }
81 |
82 | public void init(String webLoc) {
83 | this.webLoc = webLoc;
84 | }
85 | }
86 |
--------------------------------------------------------------------------------
/src/main/java/qj/tool/sql/Builder.java:
--------------------------------------------------------------------------------
1 | package qj.tool.sql;
2 |
3 | import com.google.gson.Gson;
4 | import qj.tool.sql.Template.Field1;
5 | import qj.util.Cols;
6 | import qj.util.NameCaseUtil;
7 | import qj.util.ReflectUtil;
8 | import qj.util.StringUtil;
9 | import qj.util.funct.F1;
10 | import qj.util.funct.F2;
11 | import qj.util.funct.P1;
12 |
13 | import java.lang.reflect.Field;
14 | import java.lang.reflect.Method;
15 | import java.lang.reflect.Modifier;
16 | import java.lang.reflect.Type;
17 | import java.sql.Blob;
18 | import java.sql.ResultSet;
19 | import java.sql.SQLException;
20 | import java.util.*;
21 |
22 | public class Builder {
23 |
24 | private Class clazz;
25 | private List idFields = Arrays.asList("id");
26 | private String tableName;
27 | boolean autoIncrement = true;
28 |
29 | public Builder(Class clazz) {
30 | this.clazz = clazz;
31 |
32 | tableName = NameCaseUtil.camelToHyphen(clazz.getSimpleName());
33 | }
34 |
35 | public static void main(String[] args) {
36 | System.out.println(NameCaseUtil.camelToHyphen("ChatLastRead"));
37 | }
38 |
39 |
40 | public Builder id(String... idFields) {
41 | this.idFields = Arrays.asList(idFields);
42 | return this;
43 | }
44 |
45 | HashSet dontStore = new HashSet<>();
46 | public Template build() {
47 | Template template = new Template<>(clazz);
48 | template.idFields = Cols.yield(idFields, (fName) -> field1(ReflectUtil.getField(fName, clazz)));
49 | template.dataFields = new LinkedList<>();
50 | template.tableName = tableName;
51 | template.autoIncrement = autoIncrement;
52 | eachField(clazz, (f) -> {
53 | if (dontStore.contains(f.getName())) {
54 | return;
55 | }
56 | template.dataFields.add(field1(f));
57 | });
58 | return template;
59 | }
60 |
61 | @SuppressWarnings("UnusedDeclaration")
62 | public Builder noId() {
63 | idFields = Collections.emptyList();
64 | return this;
65 | }
66 | public Builder tableName(String tableName) {
67 | this.tableName = tableName;
68 | return this;
69 | }
70 |
71 | public Field1 field1(Field field) {
72 | Field1 raw = field1_raw(field);
73 | F1, Field1> decor = fieldDecors.get(field.getName());
74 | if (decor != null) {
75 | return decor.e(raw);
76 | }
77 | return raw;
78 | }
79 |
80 | public static Field1 field1_raw(Field field) {
81 | Field1 field1 = new Field1() {
82 | @Override
83 | void setValue(Object val, M m) {
84 | if (boolean.class.equals(field.getType())) {
85 | if (val == null) {
86 | val = Boolean.FALSE;
87 | }
88 | }
89 | ReflectUtil.setFieldValue(val, field, m);
90 | }
91 | @Override
92 | Object getValue(M m) {
93 | return ReflectUtil.getFieldValue(field, m);
94 | }
95 | };
96 | field1.type = field.getGenericType();
97 | field1.sqlName = NameCaseUtil.camelToHyphen(field.getName());
98 | field1.psSetter = SQLUtil.setter(field.getType());
99 | field1.rsGet = rsGet(field.getType());
100 | return field1;
101 | }
102 |
103 | Map,Field1>> fieldDecors = new HashMap<>();
104 |
105 | private Builder embeded(String fieldName, F1,Type> convertTypeF,
106 | F1