{"id":12799,"date":"2015-12-13T16:27:00","date_gmt":"2015-12-13T15:27:00","guid":{"rendered":"https:\/\/touk.pl\/blog\/?guid=54523a580d2eea3cd98e2fa4f5d02672"},"modified":"2022-08-03T12:48:41","modified_gmt":"2022-08-03T10:48:41","slug":"primitives-and-its-wrapped-types-compatibility","status":"publish","type":"post","link":"https:\/\/touk.pl\/blog\/2015\/12\/13\/primitives-and-its-wrapped-types-compatibility\/","title":{"rendered":"Primitives and its wrapped types compatibility"},"content":{"rendered":"<h2 id=\"introduction\">Introduction<\/h2>\n<p>How often do you think about possible changes in your API? Do you consider that something required could become optional in future? How about compatibility of such change? One of this changes is going from primitive (e. g. <code>int<\/code>) to its wrapped type (e. g. <code>Integer<\/code>). Let&#8217;s check it out.<\/p>\n<h2 id=\"api---first-iteration\"><span id=\"api-first-iteration\">API &#8211; first iteration<\/span><\/h2>\n<p>Let&#8217;s start with simple DTO class <code>Dep<\/code> in our public API.<\/p>\n<pre class=\"brush: java\">public class Dep {\r\n    private int f1;<\/pre>\n<p>public int getF1(){<br \/>\nreturn f1;<br \/>\n}<\/p>\n<p>public void setF1(int f1){<br \/>\nthis.f1 = f1;<br \/>\n}<\/p>\n<p>\/\/ other fields and methods omitted<br \/>\n}<\/p>\n<p><code>f1<\/code> is obligatory field that never will be null.<\/p>\n<p>Let&#8217;s use it in <code>Main<\/code> class:<\/p>\n<pre class=\"brush: java\">public class Main {\r\n    public static void main(String... args) {\r\n        Dep dep = new Dep();\r\n        dep.setF1(123);\r\n        System.out.println(dep.getF1());\r\n    }\r\n}<\/pre>\n<p>compile it:<\/p>\n<pre class=\"brush: bash\">$ javac depInt\/Dep.java\r\n$ javac -cp depInt main\/Main.java<\/pre>\n<p>and run:<\/p>\n<pre class=\"brush: bash\">$ java -cp depInt:main Main\r\n123<\/pre>\n<p>It works.<\/p>\n<h2 id=\"api---obligatory-field-become-optional\"><span id=\"api-obligatory-field-become-optional\">API &#8211; obligatory field become optional<\/span><\/h2>\n<p>Now suppose our business requirements have changed. <code>f1<\/code> is not longer obligatory and we want possibility to set it to <code>null<\/code>.<\/p>\n<p>So we provide next iteration of <code>Dep<\/code> class where <code>f1<\/code> field has type <code>Integer<\/code>.<\/p>\n<pre class=\"brush: java\">public class Dep {\r\n    private Integer f1;<\/pre>\n<p>public Integer getF1(){<br \/>\nreturn f1;<br \/>\n}<\/p>\n<p>public void setF1(Integer f1){<br \/>\nthis.f1 = f1;<br \/>\n}<\/p>\n<p>\/\/ other fields and methods omitted<br \/>\n}<\/p>\n<p>We compile only the new <code>Dep<\/code> class because we do not want to change the <code>Main<\/code> class:<\/p>\n<pre class=\"brush: bash\">$ javac depInteger\/Dep.java<\/pre>\n<p>and run it with old <code>Main<\/code>:<\/p>\n<pre class=\"brush: bash\">$ java -cp depInteger:main Main\r\nException in thread \"main\" java.lang.NoSuchMethodError: Dep.setF1(I)V\r\n    at Main.main(Main.java:4)<\/pre>\n<p>Wow! It does not work&#8230;<\/p>\n<h2 id=\"why-does-it-not-work\">Why does it not work?<\/h2>\n<p>We can use <code>javap<\/code> tool to investigate <code>Main<\/code> class.<\/p>\n<pre class=\"brush: bash; highlight: [18, 21]\">$ javap -c main\/Main.class\r\nCompiled from \"Main.java\"\r\npublic class Main {\r\n  public Main();\r\n    Code:\r\n       0: aload_0\r\n       1: invokespecial #1                  \/\/ Method java\/lang\/Object.\"&lt;init&gt;\":()V\r\n       4: return<\/pre>\n<p>public static void main(java.lang.String&#8230;);<br \/>\nCode:<br \/>\n0: new #2 \/\/ class Dep<br \/>\n3: dup<br \/>\n4: invokespecial #3 \/\/ Method Dep.&#8221;&lt;init&gt;&#8221;:()V<br \/>\n7: astore_1<br \/>\n8: aload_1<br \/>\n9: bipush 123<br \/>\n11: invokevirtual #4 \/\/ Method Dep.setF1:(I)V<br \/>\n14: getstatic #5 \/\/ Field java\/lang\/System.out:Ljava\/io\/PrintStream;<br \/>\n17: aload_1<br \/>\n18: invokevirtual #6 \/\/ Method Dep.getF1:()I<br \/>\n21: invokevirtual #7 \/\/ Method java\/io\/PrintStream.println:(I)V<br \/>\n24: return<br \/>\n}<\/p>\n<p>The most important are 11th and 18th instructions of <code>main<\/code> method. <code>Main<\/code> lookups for methods which use <code>int<\/code> (<code>I<\/code> in method signature).<\/p>\n<p>Next let&#8217;s compile the <code>Main<\/code> class with <code>Dep<\/code> which has <code>f1<\/code> of type <code>Integer<\/code>:<\/p>\n<pre class=\"brush: bash\">javac -cp depInteger main\/Main.java<\/pre>\n<p>and use <code>javap<\/code> on this class:<\/p>\n<pre class=\"brush: bash; highlight: [19, 22]\">$ javap -c main\/Main.class\r\nCompiled from \"Main.java\"\r\npublic class Main {\r\n  public Main();\r\n    Code:\r\n       0: aload_0\r\n       1: invokespecial #1                  \/\/ Method java\/lang\/Object.\"&lt;init&gt;\":()V\r\n       4: return<\/pre>\n<p>public static void main(java.lang.String&#8230;);<br \/>\nCode:<br \/>\n0: new #2 \/\/ class Dep<br \/>\n3: dup<br \/>\n4: invokespecial #3 \/\/ Method Dep.&#8221;&lt;init&gt;&#8221;:()V<br \/>\n7: astore_1<br \/>\n8: aload_1<br \/>\n9: bipush 123<br \/>\n11: invokestatic #4 \/\/ Method java\/lang\/Integer.valueOf:(I)Ljava\/lang\/Integer;<br \/>\n14: invokevirtual #5 \/\/ Method Dep.setF1:(Ljava\/lang\/Integer;)V<br \/>\n17: getstatic #6 \/\/ Field java\/lang\/System.out:Ljava\/io\/PrintStream;<br \/>\n20: aload_1<br \/>\n21: invokevirtual #7 \/\/ Method Dep.getF1:()Ljava\/lang\/Integer;<br \/>\n24: invokevirtual #8 \/\/ Method java\/io\/PrintStream.println:(Ljava\/lang\/Object;)V<br \/>\n27: return<br \/>\n}<\/p>\n<p>Now we see the difference. The <code>main<\/code> method:<\/p>\n<ul>\n<li>converts <code>int<\/code> to <code>Integer<\/code> in instruction 11th,<\/li>\n<li>invokes method <code>setF1<\/code> which takes parameter of type <code>Integer<\/code> (<code>Ljava\/lang\/Integer;<\/code>) in instruction 14th,<\/li>\n<li>invokes method <code>getF1<\/code> which returns <code>Integer<\/code> in instruction 21st.<\/li>\n<\/ul>\n<p>These differences do not allow us to use the <code>Main<\/code> class with <code>Dep<\/code> without recompilation if we change <code>f1<\/code>.<\/p>\n<h2 id=\"how-about-groovy\">How about Groovy?<\/h2>\n<p>We have <code>GroovyMain<\/code> class which do the same as <code>Main<\/code> class written in Java.<\/p>\n<pre class=\"brush: java\">class GroovyMain {\r\n    static void main(String... args) {\r\n        Dep dep = new Dep(f1: 123)\r\n        println(dep.f1)\r\n    }\r\n}<\/pre>\n<p>We will compile <code>GroovyMain<\/code> class only with <code>Dep<\/code> which uses <code>int<\/code>:<\/p>\n<pre class=\"brush: bash\">$ groovyc -cp lib\/groovy-all-2.4.5.jar:depInt -d main main\/GroovyMain.groovy<\/pre>\n<p>It runs great as expected with <code>int<\/code>:<\/p>\n<pre class=\"brush: bash\">$ java -cp lib\/groovy-all-2.4.5.jar:depInt:main GroovyMain\r\n123<\/pre>\n<p>but with <code>Integer<\/code>&#8230; It works the same!<\/p>\n<pre class=\"brush: bash\">$ java -cp lib\/groovy-all-2.4.5.jar:depInteger:main GroovyMain\r\n123<\/pre>\n<p>Groovy is immune to such change.<\/p>\n<h3 id=\"with-compilestatic\">With CompileStatic<\/h3>\n<p>But what if we compile groovy with <a href=\"http:\/\/docs.groovy-lang.org\/next\/html\/gapi\/groovy\/transform\/CompileStatic.html\"><code>CompileStatic<\/code><\/a> annotation? This annotation instructs groovy compiler to compile class with type checking and should produce bytecode similar to <code>javac<\/code> output.<\/p>\n<p><code>GroovyMainCompileStatic<\/code> class is <code>GroovyMain<\/code> class with only <code>CompileStatic<\/code> annotation:<\/p>\n<pre class=\"brush: java\">import groovy.transform.CompileStatic<\/pre>\n<p>@CompileStatic<br \/>\nclass GroovyMainCompileStatic {<br \/>\nstatic void main(String&#8230; args) {<br \/>\nDep dep = new Dep(f1: 123)<br \/>\nprintln(dep.f1)<br \/>\n}<br \/>\n}<\/p>\n<p>When we compile this with <code>Dep<\/code> with <code>int<\/code> field:<\/p>\n<pre class=\"brush: bash\">$ groovyc -cp lib\/groovy-all-2.4.5.jar:depInt -d main main\/GroovyMainCompileStatic.groovy<\/pre>\n<p>then of course it works:<\/p>\n<pre class=\"brush: bash\">$ java -cp lib\/groovy-all-2.4.5.jar:depInt:main GroovyMainCompileStatic\r\n123<\/pre>\n<p>but with <code>Dep<\/code> with <code>Integer<\/code> field it fails like in Java:<\/p>\n<pre class=\"brush: bash\">$ java -cp lib\/groovy-all-2.4.5.jar:depInteger:main GroovyMainCompileStatic\r\nException in thread \"main\" java.lang.NoSuchMethodError: Dep.setF1(I)V\r\n    at GroovyMainCompileStatic.main(GroovyMainCompileStatic.groovy:6)<\/pre>\n<h2 id=\"conclusion\">Conclusion<\/h2>\n<p>Change from primitive to its wrapped java type is not compatible change. Bytecode which uses dependent class assumes that there will be method which consumes or returns e. g. <code>int<\/code> and cannot deal with the same class which provides such method with <code>Integer<\/code> in place of <code>int<\/code>.<\/p>\n<p>Groovy is much more flexible and could handle it, but only if we do not use <code>CompileStatic<\/code> annotation.<\/p>\n<p>The source code is available <a href=\"https:\/\/github.com\/alien11689\/primitive-and-its-wrapped-types-compatibility\">here<\/a>.<\/p>\n","protected":false},"excerpt":{"rendered":"IntroductionHow often do you think about possible changes in your API? Do you consider that something required could become optional in future? How about compatibility of such change? One of this changes is going from primitive (e. g. int) to its wrapp&#8230;\n","protected":false},"author":54,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[11],"tags":[50,68,590],"class_list":{"0":"post-12799","1":"post","2":"type-post","3":"status-publish","4":"format-standard","6":"category-development-design","7":"tag-groovy","8":"tag-java","9":"tag-primitive-types"},"_links":{"self":[{"href":"https:\/\/touk.pl\/blog\/wp-json\/wp\/v2\/posts\/12799","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/touk.pl\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/touk.pl\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/touk.pl\/blog\/wp-json\/wp\/v2\/users\/54"}],"replies":[{"embeddable":true,"href":"https:\/\/touk.pl\/blog\/wp-json\/wp\/v2\/comments?post=12799"}],"version-history":[{"count":7,"href":"https:\/\/touk.pl\/blog\/wp-json\/wp\/v2\/posts\/12799\/revisions"}],"predecessor-version":[{"id":14929,"href":"https:\/\/touk.pl\/blog\/wp-json\/wp\/v2\/posts\/12799\/revisions\/14929"}],"wp:attachment":[{"href":"https:\/\/touk.pl\/blog\/wp-json\/wp\/v2\/media?parent=12799"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/touk.pl\/blog\/wp-json\/wp\/v2\/categories?post=12799"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/touk.pl\/blog\/wp-json\/wp\/v2\/tags?post=12799"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}