Sorry

This feed does not validate.

In addition, interoperability with the widest range of feed readers could be improved by implementing the following recommendations.

Source: https://blog.bmarwell.de/feed/

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <feed xmlns="http://www.w3.org/2005/Atom">
  3.  <title>Benjamin Marwell</title>
  4.  <subtitle>Ben’s IT-Comments</subtitle>
  5.  <link href="https://blog.bmarwell.de"/>
  6.  <link rel="self" href="https://blog.bmarwell.de/feed.xml" />
  7.  <updated>2023-12-24T13:49:33Z</updated>
  8.  
  9.  <author>
  10.    <name>Benjamin Marwell</name>
  11.    <uri>https://twitter.com/@bmarwell</uri>
  12.  </author>
  13.  <id>https://blog.bmarwell.de/</id>
  14.  <generator uri="https://jbake.org/">JBake.org</generator>
  15.  <icon>/images/favicon128.png</icon>
  16.  <logo>/images/bens_it_kommentare.png</logo>
  17.  
  18.  <entry>
  19.    <!-- lang="en-GB"  -->
  20.    <title>Trickery with Maven and Multi-Release JARs</title>
  21.    <link href="https://blog.bmarwell.de/2023/10/22/trickery-with-multi-release-jars.html"/>
  22.    <id>https://blog.bmarwell.de/2023/10/22/trickery-with-multi-release-jars.html</id>
  23.    <published>2023-10-22T22:07:35Z</published>
  24.    <updated>2023-10-22T22:07:35Z</updated>
  25.    <author>
  26.      <name>Benjamin Marwell</name>
  27.    </author>
  28.    <content type="html">
  29.      &lt;div id=&quot;preamble&quot;&gt;
  30. &lt;div class=&quot;sectionbody&quot;&gt;
  31. &lt;div class=&quot;paragraph&quot;&gt;
  32. &lt;p&gt;Recently, I came across deprecation warnings in the &lt;a href=&quot;https://github.com/groovy/GMavenPlus&quot;&gt;GMavenPlus-Maven-Plugin (gplus-maven-plugin)&lt;/a&gt;.
  33. Here&amp;#8217;s how I solved it by putting a Java 8-bytecode file (class file version 52.0) into &lt;code&gt;META-INF/versions/java21&lt;/code&gt;, which is better known as a &lt;strong&gt;Multi-Release JAR&lt;/strong&gt;.&lt;/p&gt;
  34. &lt;/div&gt;
  35. &lt;div id=&quot;toc&quot; class=&quot;toc&quot;&gt;
  36. &lt;div id=&quot;toctitle&quot; class=&quot;title&quot;&gt;Table of Contents&lt;/div&gt;
  37. &lt;ul class=&quot;sectlevel1&quot;&gt;
  38. &lt;li&gt;&lt;a href=&quot;#jdk_apis_to_be_removed&quot;&gt;JDK-APIs to be removed&lt;/a&gt;&lt;/li&gt;
  39. &lt;li&gt;&lt;a href=&quot;#the_problem_imports&quot;&gt;The Problem: Imports&lt;/a&gt;&lt;/li&gt;
  40. &lt;li&gt;&lt;a href=&quot;#maven_the_intended_way&quot;&gt;Maven: The intended way&lt;/a&gt;&lt;/li&gt;
  41. &lt;li&gt;&lt;a href=&quot;#maven_the_creative_way&quot;&gt;Maven: The creative way&lt;/a&gt;&lt;/li&gt;
  42. &lt;li&gt;&lt;a href=&quot;#maven_trickery_compiling_for_jdk_30&quot;&gt;Maven trickery: Compiling for JDK 30&lt;/a&gt;&lt;/li&gt;
  43. &lt;li&gt;&lt;a href=&quot;#conclusion&quot;&gt;Conclusion&lt;/a&gt;&lt;/li&gt;
  44. &lt;/ul&gt;
  45. &lt;/div&gt;
  46. &lt;/div&gt;
  47. &lt;/div&gt;
  48. &lt;div class=&quot;sect1&quot;&gt;
  49. &lt;h2 id=&quot;jdk_apis_to_be_removed&quot;&gt;JDK-APIs to be removed&lt;/h2&gt;
  50. &lt;div class=&quot;sectionbody&quot;&gt;
  51. &lt;div class=&quot;paragraph&quot;&gt;
  52. &lt;p&gt;One of the APIs which are deprecated for removal is the infamous &lt;a href=&quot;https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/lang/SecurityManager.html&quot;&gt;SecurityManager&lt;/a&gt;.
  53. As you can tell from the documentation, it is not only deprecated; instead, it is deprecated for removal.
  54. This means, code relying on these classes are going to break at some point in the future.
  55. While I expect them to work for quite a bit longer (JDK 30 or so? Who knows?), many applications do either  not really need then &lt;strong&gt;or&lt;/strong&gt; the functionality can be replaced somehow.&lt;/p&gt;
  56. &lt;/div&gt;
  57. &lt;/div&gt;
  58. &lt;/div&gt;
  59. &lt;div class=&quot;sect1&quot;&gt;
  60. &lt;h2 id=&quot;the_problem_imports&quot;&gt;The Problem: Imports&lt;/h2&gt;
  61. &lt;div class=&quot;sectionbody&quot;&gt;
  62. &lt;div class=&quot;paragraph&quot;&gt;
  63. &lt;p&gt;The hardest problem to solve: You cannot use imports starting with Java 21 if you want to avoid all warnings.
  64. Now, you could just work with reflection, which is cumbersome.
  65. Another idea would be to move the code into its own class.
  66. But the moment you begin building with a version of Java which has the &lt;code&gt;SecurityManager&lt;/code&gt; removed,  your build will break.&lt;/p&gt;
  67. &lt;/div&gt;
  68. &lt;div class=&quot;paragraph&quot;&gt;
  69. &lt;p&gt;Luckily, Multi-Release JARs can help us get this problem out of the way.&lt;/p&gt;
  70. &lt;/div&gt;
  71. &lt;/div&gt;
  72. &lt;/div&gt;
  73. &lt;div class=&quot;sect1&quot;&gt;
  74. &lt;h2 id=&quot;maven_the_intended_way&quot;&gt;Maven: The intended way&lt;/h2&gt;
  75. &lt;div class=&quot;sectionbody&quot;&gt;
  76. &lt;div class=&quot;paragraph&quot;&gt;
  77. &lt;p&gt;First, you decide which class is to be replaced in higher JDK versions by another version of itself.
  78. In my case (the groovy plugin), I created a file &lt;code&gt;SecurityManagerSetter.java&lt;/code&gt; with two implementations:&lt;/p&gt;
  79. &lt;/div&gt;
  80. &lt;div class=&quot;olist arabic&quot;&gt;
  81. &lt;ol class=&quot;arabic&quot;&gt;
  82. &lt;li&gt;
  83. &lt;p&gt;The Default implementation in &lt;code&gt;src/main/java&lt;/code&gt;&lt;/p&gt;
  84. &lt;/li&gt;
  85. &lt;li&gt;
  86. &lt;p&gt;The logging-only implementation in &lt;code&gt;src/main/java21&lt;/code&gt;.&lt;/p&gt;
  87. &lt;/li&gt;
  88. &lt;/ol&gt;
  89. &lt;/div&gt;
  90. &lt;div class=&quot;paragraph&quot;&gt;
  91. &lt;p&gt;Usually, you create a new source directory (e.g. &lt;code&gt;src/main/java21&lt;/code&gt;) with the source file mentioned above and configure a new maven-compiler-plugin execution like so:&lt;/p&gt;
  92. &lt;/div&gt;
  93. &lt;div class=&quot;listingblock&quot;&gt;
  94. &lt;div class=&quot;title&quot;&gt;Classical Multi-Release JAR single-module compilation&lt;/div&gt;
  95. &lt;div class=&quot;content&quot;&gt;
  96. &lt;pre class=&quot;highlightjs highlight&quot;&gt;&lt;code class=&quot;language-xml hljs&quot; data-lang=&quot;xml&quot;&gt;&amp;lt;build&amp;gt;
  97.  &amp;lt;plugins&amp;gt;
  98.    &amp;lt;plugin&amp;gt;
  99.      &amp;lt;groupId&amp;gt;org.apache.maven.plugins&amp;lt;/groupId&amp;gt;
  100.      &amp;lt;artifactId&amp;gt;maven-compiler-plugin&amp;lt;/artifactId&amp;gt;
  101.      &amp;lt;executions&amp;gt;
  102.        &amp;lt;execution&amp;gt;
  103.          &amp;lt;id&amp;gt;compile-java21&amp;lt;/id&amp;gt;
  104.          &amp;lt;phase&amp;gt;compile&amp;lt;/phase&amp;gt;
  105.          &amp;lt;goals&amp;gt;
  106.            &amp;lt;goal&amp;gt;compile&amp;lt;/goal&amp;gt;
  107.          &amp;lt;/goals&amp;gt;
  108.          &amp;lt;configuration&amp;gt;
  109.            &amp;lt;release&amp;gt;21&amp;lt;/release&amp;gt;
  110.            &amp;lt;compileSourceRoots&amp;gt;
  111.                &amp;lt;compileSourceRoot&amp;gt;${project.basedir}/src/main/java21&amp;lt;/compileSourceRoot&amp;gt;
  112.            &amp;lt;/compileSourceRoots&amp;gt;
  113.            &amp;lt;multiReleaseOutput&amp;gt;true&amp;lt;/multiReleaseOutput&amp;gt;
  114.          &amp;lt;/configuration&amp;gt;
  115.        &amp;lt;/execution&amp;gt;
  116.      &amp;lt;/executions&amp;gt;
  117.    &amp;lt;/plugin&amp;gt;
  118.  &amp;lt;/plugins&amp;gt;
  119. &amp;lt;/build&amp;gt;&lt;/code&gt;&lt;/pre&gt;
  120. &lt;/div&gt;
  121. &lt;/div&gt;
  122. &lt;div class=&quot;paragraph&quot;&gt;
  123. &lt;p&gt;However, this is ugly for a very specific reason:&lt;/p&gt;
  124. &lt;/div&gt;
  125. &lt;div class=&quot;ulist&quot;&gt;
  126. &lt;ul&gt;
  127. &lt;li&gt;
  128. &lt;p&gt;You either need a JDK which spans all wanted release targets (in this case: Java 8 and Java 21)&lt;br&gt;
  129. Or&lt;/p&gt;
  130. &lt;/li&gt;
  131. &lt;li&gt;
  132. &lt;p&gt;you &lt;a href=&quot;https://maarten.mulders.it/2021/03/introduction-to-maven-toolchains/&quot;&gt;need to use Maven toolchains&lt;/a&gt; to start multiple compilation runs.&lt;/p&gt;
  133. &lt;/li&gt;
  134. &lt;/ul&gt;
  135. &lt;/div&gt;
  136. &lt;div class=&quot;paragraph&quot;&gt;
  137. &lt;p&gt;In this case, both options are an &lt;em&gt;overkill&lt;/em&gt;, because we just need to replace a single file with e Java 21 version.
  138. Currently, the plugin only needs a single JDK which can produce Java 8 bytecode, which can be anything between a JDK 8 and JDK 21 (at the time of writing this article).
  139. I would not want to change that for a single file.&lt;/p&gt;
  140. &lt;/div&gt;
  141. &lt;/div&gt;
  142. &lt;/div&gt;
  143. &lt;div class=&quot;sect1&quot;&gt;
  144. &lt;h2 id=&quot;maven_the_creative_way&quot;&gt;Maven: The creative way&lt;/h2&gt;
  145. &lt;div class=&quot;sectionbody&quot;&gt;
  146. &lt;div class=&quot;paragraph&quot;&gt;
  147. &lt;p&gt;So, who said we need to have a Java 21 bytecode file (class file version 65.0) in our &lt;code&gt;META-INF/versions/java21&lt;/code&gt; folder?
  148. I asked &lt;a href=&quot;https://nipafx.dev/multi-release-jars-multiple-java-versions/&quot;&gt;Nicolai Parlog who wrote this article about Multi-Release JARs&lt;/a&gt;, and he confirmed my guess:
  149. The class file in the Java 21 folder can be anything &lt;strong&gt;up to&lt;/strong&gt; (including) Java 21 class files.&lt;/p&gt;
  150. &lt;/div&gt;
  151. &lt;div class=&quot;paragraph&quot;&gt;
  152. &lt;p&gt;While the Maven documentation currently says, &lt;code&gt;outputDirectory&lt;/code&gt; is not writable, Maven 3 does not actually enforce this restriction.
  153. For the &lt;a href=&quot;https://github.com/apache/maven-compiler-plugin/pull/202&quot;&gt;maven-compiler-plugin v3.12.0 I created a Pull Request to remove that restriction&lt;/a&gt;.&lt;/p&gt;
  154. &lt;/div&gt;
  155. &lt;div class=&quot;paragraph&quot;&gt;
  156. &lt;p&gt;With that out of the way, we can start compiling files with Java 8 into the Java 21 directory like so:&lt;/p&gt;
  157. &lt;/div&gt;
  158. &lt;div class=&quot;listingblock&quot;&gt;
  159. &lt;div class=&quot;content&quot;&gt;
  160. &lt;pre class=&quot;highlightjs highlight&quot;&gt;&lt;code class=&quot;language-xml hljs&quot; data-lang=&quot;xml&quot;&gt;&amp;lt;build&amp;gt;
  161.  &amp;lt;plugins&amp;gt;
  162.    &amp;lt;plugin&amp;gt;
  163.      &amp;lt;groupId&amp;gt;org.apache.maven.plugins&amp;lt;/groupId&amp;gt;
  164.      &amp;lt;artifactId&amp;gt;maven-compiler-plugin&amp;lt;/artifactId&amp;gt;
  165.        &amp;lt;executions&amp;gt;
  166.          &amp;lt;execution&amp;gt;
  167.            &amp;lt;id&amp;gt;compile-java21&amp;lt;/id&amp;gt;
  168.            &amp;lt;phase&amp;gt;compile&amp;lt;/phase&amp;gt;
  169.            &amp;lt;goals&amp;gt;
  170.              &amp;lt;goal&amp;gt;compile&amp;lt;/goal&amp;gt;
  171.            &amp;lt;/goals&amp;gt;
  172.            &amp;lt;configuration&amp;gt;
  173.              &amp;lt;compileSourceRoots&amp;gt;
  174.                &amp;lt;compileSourceroot&amp;gt;${project.basedir}/src/main/java21&amp;lt;/compileSourceroot&amp;gt;
  175.              &amp;lt;/compileSourceRoots&amp;gt;
  176.              &amp;lt;!-- cannot use multireleaseOutput, because we are creating a Java 8 class file --&amp;gt;
  177.              &amp;lt;outputDirectory&amp;gt;${project.build.outputDirectory}/META-INF/versions/21&amp;lt;/outputDirectory&amp;gt;
  178.            &amp;lt;/configuration&amp;gt;
  179.          &amp;lt;/execution&amp;gt;
  180.        &amp;lt;/executions&amp;gt;
  181.    &amp;lt;/plugin&amp;gt;
  182.  &amp;lt;/plugins&amp;gt;
  183. &amp;lt;/build&amp;gt;&lt;/code&gt;&lt;/pre&gt;
  184. &lt;/div&gt;
  185. &lt;/div&gt;
  186. &lt;div class=&quot;paragraph&quot;&gt;
  187. &lt;p&gt;This is a simple trick: We did not specify &lt;code&gt;multiReleaseOutput&lt;/code&gt;, which implicitly requires the &lt;code&gt;release&lt;/code&gt; parameter to be set and therefore enforces the target bytecode to be the version of the &lt;code&gt;release&lt;/code&gt; parameter.
  188. However, as Nicolai hinted on 𝕏 (formerly Twitter), there is no such restriction enforced by the JDK:&lt;/p&gt;
  189. &lt;/div&gt;
  190. &lt;blockquote class=&quot;twitter-tweet&quot;&gt;&lt;p lang=&quot;en&quot; dir=&quot;ltr&quot;&gt;That should work, yes.&lt;br&gt;&lt;br&gt;I like that idea. Any chance you can post a summary of what you did once you get it working?&lt;/p&gt;&amp;mdash; Nicolai Parlog 🇺🇦🕊️ (@nipafx) &lt;a href=&quot;https://twitter.com/nipafx/status/1715285877205733800?ref_src=twsrc%5Etfw&quot;&gt;October 20, 2023&lt;/a&gt;&lt;/blockquote&gt; &lt;script async src=&quot;https://platform.twitter.com/widgets.js&quot; charset=&quot;utf-8&quot;&gt;&lt;/script&gt;
  191. &lt;div class=&quot;paragraph&quot;&gt;
  192. &lt;p&gt;Hello, Nicolai. 👋🏻
  193. This is the summary! 😊&lt;/p&gt;
  194. &lt;/div&gt;
  195. &lt;div class=&quot;paragraph&quot;&gt;
  196. &lt;p&gt;Back to the XML snippet&amp;#8201;&amp;#8212;&amp;#8201;so, what do we actually do here?&lt;/p&gt;
  197. &lt;/div&gt;
  198. &lt;div class=&quot;paragraph&quot;&gt;
  199. &lt;p&gt;We &lt;strong&gt;only&lt;/strong&gt; compile files from &lt;code&gt;src/main/java21&lt;/code&gt; and put them into &lt;code&gt;target/classes/META-INF/versions/21&lt;/code&gt;.
  200. This can be done with any JDK, so the build will still run on Java 8, 11, 17, 21… you name it.&lt;/p&gt;
  201. &lt;/div&gt;
  202. &lt;/div&gt;
  203. &lt;/div&gt;
  204. &lt;div class=&quot;sect1&quot;&gt;
  205. &lt;h2 id=&quot;maven_trickery_compiling_for_jdk_30&quot;&gt;Maven trickery: Compiling for JDK 30&lt;/h2&gt;
  206. &lt;div class=&quot;sectionbody&quot;&gt;
  207. &lt;div class=&quot;paragraph&quot;&gt;
  208. &lt;p&gt;Remember I mentioned JDK 30 a few paragraphs into this article?
  209. This is because at the time of writing, JDK 30 was not available for a loooong time: JDK 21 just came out last month, not even by all vendors due to Oracle‘s TCK situation.&lt;/p&gt;
  210. &lt;/div&gt;
  211. &lt;div class=&quot;paragraph&quot;&gt;
  212. &lt;p&gt;That said, with this trick where we uncouple the &lt;code&gt;META-INF/versions/javaNN&lt;/code&gt; directory from both the &lt;code&gt;release&lt;/code&gt; parameter of the maven-compiler-plugin and the JDK which invoked maven (or the toolchain which invoked &lt;code&gt;javac&lt;/code&gt;, for that matter), we can name our output directory anything you want!&lt;/p&gt;
  213. &lt;/div&gt;
  214. &lt;div class=&quot;paragraph&quot;&gt;
  215. &lt;p&gt;How is this helpful?&lt;/p&gt;
  216. &lt;/div&gt;
  217. &lt;div class=&quot;paragraph&quot;&gt;
  218. &lt;p&gt;In case you got an information that Java 30 will actually drop the &lt;code&gt;SecurityManager&lt;/code&gt; (again, this is just a wild assumption and most probably wrong), you can now put your &lt;code&gt;SecurityManager&lt;/code&gt;-cleansed Java 8 class file into &lt;code&gt;META-INF/versions/java30&lt;/code&gt;, and it will start working the moment the first Java 30 early access build arrives!
  219. Isn’t this neat? 😊&lt;/p&gt;
  220. &lt;/div&gt;
  221. &lt;div class=&quot;paragraph&quot;&gt;
  222. &lt;p&gt;This also enables using a single JDK version when, by definition, multiple JDKs would have been required by the bytecode versions: JDK 30 would probably not have support for &lt;code&gt;release=8&lt;/code&gt; anymore.&lt;/p&gt;
  223. &lt;/div&gt;
  224. &lt;/div&gt;
  225. &lt;/div&gt;
  226. &lt;div class=&quot;sect1&quot;&gt;
  227. &lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
  228. &lt;div class=&quot;sectionbody&quot;&gt;
  229. &lt;div class=&quot;paragraph&quot;&gt;
  230. &lt;p&gt;In this blog post we discovered how we can avoid toolchain invocations or avoid restricting the build to higher JDK versions for simple use cases.&lt;/p&gt;
  231. &lt;/div&gt;
  232. &lt;div class=&quot;paragraph&quot;&gt;
  233. &lt;p&gt;Did you find this helpful or do you even have similar use cases?
  234. Let Nicolai and me know on Twitter (now 𝕏)!&lt;/p&gt;
  235. &lt;/div&gt;
  236. &lt;/div&gt;
  237. &lt;/div&gt;
  238.    </content>
  239.  </entry>
  240.  
  241.  <entry>
  242.    <!-- lang="en-GB"  -->
  243.    <title>Why you should avoid if-else in your code</title>
  244.    <link href="https://blog.bmarwell.de/2023/05/11/why-avoid-if-else.html"/>
  245.    <id>https://blog.bmarwell.de/2023/05/11/why-avoid-if-else.html</id>
  246.    <published>2023-05-11T22:07:35Z</published>
  247.    <updated>2023-05-11T22:07:35Z</updated>
  248.    <author>
  249.      <name>Benjamin Marwell</name>
  250.    </author>
  251.    <content type="html">
  252.      &lt;div id=&quot;preamble&quot;&gt;
  253. &lt;div class=&quot;sectionbody&quot;&gt;
  254. &lt;div class=&quot;paragraph&quot;&gt;
  255. &lt;p&gt;&lt;strong&gt;if/else&lt;/strong&gt; statements are one of the most used statements of almost every programming language.
  256. Whenever you create new source files, a few methods you write will always contain an &lt;code&gt;if-else&lt;/code&gt; statement at some point.
  257. I tend to refactor these statements out, so that I have almost no &lt;code&gt;else&lt;/code&gt; statement in my code.&lt;/p&gt;
  258. &lt;/div&gt;
  259. &lt;div class=&quot;paragraph&quot;&gt;
  260. &lt;p&gt;Read on why I chose to avoid &lt;code&gt;else&lt;/code&gt; most of the time and how I apply the rules on an example on a random method taken from Objectos.&lt;/p&gt;
  261. &lt;/div&gt;
  262. &lt;/div&gt;
  263. &lt;/div&gt;
  264. &lt;div class=&quot;sect1&quot;&gt;
  265. &lt;h2 id=&quot;why_avoiding_else_is_good_rationale&quot;&gt;Why avoiding else is good - rationale&lt;/h2&gt;
  266. &lt;div class=&quot;sectionbody&quot;&gt;
  267. &lt;div class=&quot;paragraph&quot;&gt;
  268. &lt;p&gt;All the following statements can be disproved easily.
  269. They are mostly a design choice you have to make (or not) at some point.&lt;/p&gt;
  270. &lt;/div&gt;
  271. &lt;div class=&quot;sect2&quot;&gt;
  272. &lt;h3 id=&quot;you_do_not_need_else&quot;&gt;You do not need &lt;code&gt;else&lt;/code&gt;&lt;/h3&gt;
  273. &lt;div class=&quot;paragraph&quot;&gt;
  274. &lt;p&gt;This might sound silly at first, because this statement could be true for so many other statements:
  275. Loops could be replaced by &lt;code&gt;goto&lt;/code&gt; statements, but you have probably chosen to avoid &lt;code&gt;goto&lt;/code&gt; instead.
  276. That said, it is just one more »clean code« rule.&lt;/p&gt;
  277. &lt;/div&gt;
  278. &lt;div class=&quot;paragraph&quot;&gt;
  279. &lt;p&gt;Why does it matter?&lt;br&gt;
  280. Look at the alternatives and what will happen if you follow this rule.&lt;/p&gt;
  281. &lt;/div&gt;
  282. &lt;/div&gt;
  283. &lt;div class=&quot;sect2&quot;&gt;
  284. &lt;h3 id=&quot;use_guard_clauses&quot;&gt;Use guard clauses&lt;/h3&gt;
  285. &lt;div class=&quot;paragraph&quot;&gt;
  286. &lt;p&gt;If you are coding for a while now, you should have stumbled about the idea of using
  287. &lt;a href=&quot;https://en.wikipedia.org/wiki/Guard_(computer_science)&quot;&gt;Guards&lt;/a&gt;.
  288. In short: Put your exceptional cases at the top of your methods and return early.
  289. This will allow your main logic flow after all the guard clauses, so you do not clutter your code with unnecessary &lt;code&gt;if&lt;/code&gt;-statements.&lt;/p&gt;
  290. &lt;/div&gt;
  291. &lt;div class=&quot;paragraph&quot;&gt;
  292. &lt;p&gt;One might say a disadvantage of guard clauses is the fact that you use multiple &lt;code&gt;return&lt;/code&gt; statements now.
  293. However, considering the alternative is using multiple, mutable state variables within your method, I consider multiple return statements a much lesser evil.&lt;/p&gt;
  294. &lt;/div&gt;
  295. &lt;/div&gt;
  296. &lt;div class=&quot;sect2&quot;&gt;
  297. &lt;h3 id=&quot;replace_else_with_methods&quot;&gt;Replace &lt;code&gt;else&lt;/code&gt; with methods&lt;/h3&gt;
  298. &lt;div class=&quot;paragraph&quot;&gt;
  299. &lt;p&gt;The second rule to follow is replacing variable assignments inside &lt;code&gt;if-else&lt;/code&gt; statements with an extracted method.&lt;/p&gt;
  300. &lt;/div&gt;
  301. &lt;div class=&quot;paragraph&quot;&gt;
  302. &lt;p&gt;Applying this rule has multiple advantages:&lt;/p&gt;
  303. &lt;/div&gt;
  304. &lt;div class=&quot;olist arabic&quot;&gt;
  305. &lt;ol class=&quot;arabic&quot;&gt;
  306. &lt;li&gt;
  307. &lt;p&gt;&lt;strong&gt;All variables can be (implicitly) &lt;code&gt;final&lt;/code&gt; and unmodifiable.&lt;/strong&gt;&lt;br&gt;
  308. This is also beneficial for the runtime performance of your code, as the compiler can apply more optimizations.&lt;/p&gt;
  309. &lt;/li&gt;
  310. &lt;li&gt;
  311. &lt;p&gt;&lt;strong&gt;You can apply the guard clauses in your new method.&lt;/strong&gt;&lt;br&gt;
  312. Now your extracted method will also be split into a »special« logic and a »main« logic.&lt;br&gt;&lt;/p&gt;
  313. &lt;/li&gt;
  314. &lt;li&gt;
  315. &lt;p&gt;&lt;strong&gt;The extracted method has a name.&lt;/strong&gt;&lt;br&gt;
  316. Be sure to give the method a good name.
  317. As it now has a new, single responsibility (i.e. returning a value for a new final variable of another method), it should be easy for you to find a meaningful name for your new method.&lt;/p&gt;
  318. &lt;/li&gt;
  319. &lt;/ol&gt;
  320. &lt;/div&gt;
  321. &lt;/div&gt;
  322. &lt;div class=&quot;sect2&quot;&gt;
  323. &lt;h3 id=&quot;have_your_main_logic_non_indented_by_avoiding_else&quot;&gt;Have your main logic non-indented by avoiding &lt;code&gt;else&lt;/code&gt;&lt;/h3&gt;
  324. &lt;div class=&quot;paragraph&quot;&gt;
  325. &lt;p&gt;If you followed the two rules above, you should now see an important effect:
  326. All your »main logic« is at the end of the method and on the main indentation level.
  327. This makes it easier to follow and to read.
  328. It also allows easier refactoring if at any point in the future you decide to extract more methods or to implement new logic.&lt;/p&gt;
  329. &lt;/div&gt;
  330. &lt;/div&gt;
  331. &lt;/div&gt;
  332. &lt;/div&gt;
  333. &lt;div class=&quot;sect1&quot;&gt;
  334. &lt;h2 id=&quot;no_else_example_applying_the_rules&quot;&gt;No-&lt;code&gt;else&lt;/code&gt;-example: Applying the rules&lt;/h2&gt;
  335. &lt;div class=&quot;sectionbody&quot;&gt;
  336. &lt;div class=&quot;paragraph&quot;&gt;
  337. &lt;p&gt;For this example, I took a random method of &lt;a href=&quot;https://github.com/objectos/objectos/tree/88eca8d6d4dcb66208d7bcf183e5a31da6a343b0&quot;&gt;Macrio Endo‘s Objectos&lt;/a&gt;.&lt;/p&gt;
  338. &lt;/div&gt;
  339. &lt;div class=&quot;sect2&quot;&gt;
  340. &lt;h3 id=&quot;the_original_code&quot;&gt;The original code&lt;/h3&gt;
  341. &lt;div class=&quot;paragraph&quot;&gt;
  342. &lt;p&gt;This is the original code from &lt;code&gt;InternalApi.java&lt;/code&gt;.
  343. Interestingly, this method declares two non-final variables and uses a few &lt;code&gt;if-else-if&lt;/code&gt; statements.&lt;/p&gt;
  344. &lt;/div&gt;
  345. &lt;div class=&quot;listingblock&quot;&gt;
  346. &lt;div class=&quot;title&quot;&gt;InternalApi#elemItem(Object)&lt;/div&gt;
  347. &lt;div class=&quot;content&quot;&gt;
  348. &lt;pre class=&quot;highlightjs highlight&quot;&gt;&lt;code class=&quot;language-java hljs&quot; data-lang=&quot;java&quot;&gt;class InternalApi {
  349.  private void elemItem(Object obj) {
  350.    int offset;
  351.    int kind;
  352.  
  353.    if (obj instanceof JavaTemplate._Item item) {
  354.      offset = 0;
  355.  
  356.      kind = LOCAL;
  357.    } else if (
  358.      obj == _Ext.INSTANCE || obj instanceof External || obj instanceof String) {
  359.      offset = 1;
  360.  
  361.      kind = EXT;
  362.    } else if (obj == _Include.INSTANCE) {
  363.      offset = 2;
  364.  
  365.      kind = LAMBDA;
  366.    } else {
  367.      throw new UnsupportedOperationException(
  368.        &quot;Implement me :: obj=&quot; + obj);
  369.    }
  370.  
  371.    int index = stackPeek(offset);
  372.  
  373.    index = levelSearch(index, kind);
  374.  
  375.    if (kind != LAMBDA) {
  376.      int levelValue = levelGet(index);
  377.  
  378.      int proto = protoGet(levelValue++);
  379.  
  380.      protoAdd(proto, levelValue);
  381.    } else {
  382.      elemCntx0lambda(index);
  383.    }
  384.  
  385.    stackset(offset, index);
  386.  }
  387. }&lt;/code&gt;&lt;/pre&gt;
  388. &lt;/div&gt;
  389. &lt;/div&gt;
  390. &lt;/div&gt;
  391. &lt;div class=&quot;sect2&quot;&gt;
  392. &lt;h3 id=&quot;refactor_out_the_if_else_block&quot;&gt;Refactor out the if-else-block.&lt;/h3&gt;
  393. &lt;div class=&quot;paragraph&quot;&gt;
  394. &lt;p&gt;The first step is to extract the &lt;code&gt;if-else&lt;/code&gt; block.
  395. You can use your IDE. IntelliJ will in fact do what I would have done.
  396. Since we have two variables set, we need to define a new &lt;code&gt;Tuple&lt;/code&gt;-like class.
  397. Luckily we are on Java 17 and can use a local private &lt;code&gt;record&lt;/code&gt; class for this.&lt;/p&gt;
  398. &lt;/div&gt;
  399. &lt;div class=&quot;listingblock&quot;&gt;
  400. &lt;div class=&quot;title&quot;&gt;InternalApi#elemItem(Object) after applying the first refactoring&lt;/div&gt;
  401. &lt;div class=&quot;content&quot;&gt;
  402. &lt;pre class=&quot;highlightjs highlight&quot;&gt;&lt;code class=&quot;language-java hljs&quot; data-lang=&quot;java&quot;&gt;class InternalApi {
  403.  private record OffsetKindResult(int offset, int kind) {}
  404.  
  405.  private void elemItem(Object obj) {
  406.    final var offsetKind = getOffsetKind(obj);
  407.  
  408.    int index = stackPeek(offsetKind.offset());
  409.  
  410.    index = levelSearch(index, offsetKind.kind());
  411.  
  412.    if (offsetKind.kind() != LAMBDA) {
  413.      int levelValue = levelGet(index);
  414.  
  415.      int proto = protoGet(levelValue++);
  416.  
  417.      protoAdd(proto, levelValue);
  418.    } else {
  419.      elemCntx0lambda(index);
  420.    }
  421.  
  422.    stackset(offsetKind.offset(), index);
  423.  }
  424.  
  425.  private static OffsetKindResult getOffsetKind(Object obj) {
  426.    int offset;
  427.    int kind;
  428.  
  429.    if (obj instanceof _Item item) {
  430.      offset = 0;
  431.  
  432.      kind = LOCAL;
  433.    } else if (
  434.      obj == _Ext.INSTANCE || obj instanceof External || obj instanceof String) {
  435.      offset = 1;
  436.  
  437.      kind = EXT;
  438.    } else if (obj == _Include.INSTANCE) {
  439.      offset = 2;
  440.  
  441.      kind = LAMBDA;
  442.    } else {
  443.      throw new UnsupportedOperationException(
  444.        &quot;Implement me :: obj=&quot; + obj);
  445.    }
  446.  
  447.    return new OffsetKindResult(offset, kind);
  448.  }
  449. }&lt;/code&gt;&lt;/pre&gt;
  450. &lt;/div&gt;
  451. &lt;/div&gt;
  452. &lt;div class=&quot;paragraph&quot;&gt;
  453. &lt;p&gt;The main logic is clearer already.&lt;/p&gt;
  454. &lt;/div&gt;
  455. &lt;div class=&quot;paragraph&quot;&gt;
  456. &lt;p&gt;Now, let&amp;#8217;s replace all the else statements with guard clauses.&lt;/p&gt;
  457. &lt;/div&gt;
  458. &lt;/div&gt;
  459. &lt;div class=&quot;sect2&quot;&gt;
  460. &lt;h3 id=&quot;refactoring_getoffsetkind&quot;&gt;Refactoring getOffsetKind&lt;/h3&gt;
  461. &lt;div class=&quot;listingblock&quot;&gt;
  462. &lt;div class=&quot;content&quot;&gt;
  463. &lt;pre class=&quot;highlightjs highlight&quot;&gt;&lt;code class=&quot;language-java hljs&quot; data-lang=&quot;java&quot;&gt;class InternalApi {
  464.  private static OffsetKindResult getOffsetKind(Object obj) {
  465.    if (obj instanceof _Item) {
  466.      return new OffsetKindResult(0, LOCAL);
  467.    }
  468.  
  469.    if (obj == _Ext.INSTANCE || obj instanceof External || obj instanceof String) {
  470.      return new OffsetKindResult(1, EXT);
  471.    }
  472.  
  473.    if (obj == _Include.INSTANCE) {
  474.      return new OffsetKindResult(2, LAMBDA);
  475.    }
  476.  
  477.    throw new UnsupportedOperationException(&quot;Implement me :: obj=&quot; + obj);
  478.  }
  479. }&lt;/code&gt;&lt;/pre&gt;
  480. &lt;/div&gt;
  481. &lt;/div&gt;
  482. &lt;div class=&quot;paragraph&quot;&gt;
  483. &lt;p&gt;That&amp;#8217;s much shorter already!
  484. You can already see some benefits:
  485. There are only a few cases which actually return a valid result.
  486. The most generic case (not an &lt;code&gt;_Item&lt;/code&gt; nor an &lt;code&gt;_Include.INSTANCE&lt;/code&gt; nor &lt;code&gt;External&lt;/code&gt; or alike) will throw an Exception.
  487. We also got rid of the local variables.&lt;/p&gt;
  488. &lt;/div&gt;
  489. &lt;div class=&quot;paragraph&quot;&gt;
  490. &lt;p&gt;I (personally) find this much easier on the eyes to read.&lt;/p&gt;
  491. &lt;/div&gt;
  492. &lt;/div&gt;
  493. &lt;div class=&quot;sect2&quot;&gt;
  494. &lt;h3 id=&quot;extracting_the_other_if_else&quot;&gt;Extracting the other &lt;code&gt;if-else&lt;/code&gt;&lt;/h3&gt;
  495. &lt;div class=&quot;listingblock&quot;&gt;
  496. &lt;div class=&quot;content&quot;&gt;
  497. &lt;pre class=&quot;highlightjs highlight&quot;&gt;&lt;code class=&quot;language-java hljs&quot; data-lang=&quot;java&quot;&gt;class InternalApi {
  498.  private void elemItem(Object obj) {
  499.    final var offsetKind = getOffsetKind(obj);
  500.  
  501.    int index = stackPeek(offsetKind.offset());
  502.  
  503.    index = levelSearch(index, offsetKind.kind());
  504.  
  505.    modifyLambdaOrProto(offsetKind, index);
  506.  
  507.    stackset(offsetKind.offset(), index);
  508.  }
  509.  
  510.  private void modifyLambdaOrProto(OffsetKindResult offsetKind, int index) {
  511.    if (offsetKind.kind() != LAMBDA) {
  512.      int levelValue = levelGet(index);
  513.  
  514.      int proto = protoGet(levelValue++);
  515.  
  516.      protoAdd(proto, levelValue);
  517.    } else {
  518.      elemCntx0lambda(index);
  519.    }
  520.  }
  521. }&lt;/code&gt;&lt;/pre&gt;
  522. &lt;/div&gt;
  523. &lt;/div&gt;
  524. &lt;div class=&quot;paragraph&quot;&gt;
  525. &lt;p&gt;Now let&amp;#8217;s apply our »no-else«-rule.
  526. This is a little different from the example above, because I will reverse the if-order here.
  527. I want to handle the single-special-case first.
  528. Before our refactoring, we check if something is NOT a lambda.
  529. The »special lambda logic« follows in the else branch, which is exactly what I want to avoid.&lt;/p&gt;
  530. &lt;/div&gt;
  531. &lt;div class=&quot;paragraph&quot;&gt;
  532. &lt;p&gt;Look how by adding a single return statement and reversing the logic,
  533. we can move the main logic (not lambda) into the first level of indentation.&lt;/p&gt;
  534. &lt;/div&gt;
  535. &lt;div class=&quot;listingblock&quot;&gt;
  536. &lt;div class=&quot;content&quot;&gt;
  537. &lt;pre class=&quot;highlightjs highlight&quot;&gt;&lt;code class=&quot;language-java hljs&quot; data-lang=&quot;java&quot;&gt;class InternalApi {
  538.  private void modifyLambdaOrProto(OffsetKindResult offsetKind, int index) {
  539.    if (offsetKind.kind() == LAMBDA) {
  540.      // special case: Lambda handling differs from all other kinds.
  541.      elemCntx0lambda(index);
  542.      return;
  543.    }
  544.  
  545.    int levelValue = levelGet(index);
  546.    int proto = protoGet(levelValue++);
  547.    protoAdd(proto, levelValue);
  548.  }
  549. }&lt;/code&gt;&lt;/pre&gt;
  550. &lt;/div&gt;
  551. &lt;/div&gt;
  552. &lt;/div&gt;
  553. &lt;div class=&quot;sect2&quot;&gt;
  554. &lt;h3 id=&quot;the_final_code&quot;&gt;The final code&lt;/h3&gt;
  555. &lt;div class=&quot;paragraph&quot;&gt;
  556. &lt;p&gt;After refactoring, we have this final code.
  557. I added a few comments for clarity.
  558. Please note how each method now naturally has one responsibility without having given it much thought.
  559. We didn&amp;#8217;t even know what the method does.&lt;/p&gt;
  560. &lt;/div&gt;
  561. &lt;div class=&quot;listingblock&quot;&gt;
  562. &lt;div class=&quot;content&quot;&gt;
  563. &lt;pre class=&quot;highlightjs highlight&quot;&gt;&lt;code class=&quot;language-java hljs&quot; data-lang=&quot;java&quot;&gt;class InternalApi {
  564.  private record OffsetKindResult(int offset, int kind) {}
  565.  
  566.  private void elemItem(Object obj) {
  567.    // get offset and kind or throw early.
  568.    final var offsetKind = getOffsetKind(obj);
  569.  
  570.    int index = stackPeek(offsetKind.offset());
  571.    index = levelSearch(index, offsetKind.kind());
  572.  
  573.    modifyLambdaOrProto(offsetKind, index);
  574.  
  575.    stackset(offsetKind.offset(), index);
  576.  }
  577.  
  578.  private void modifyLambdaOrProto(OffsetKindResult offsetKind, int index) {
  579.    if (offsetKind.kind() == LAMBDA) {
  580.      // handle the LAMBDA special case.
  581.      elemCntx0lambda(index);
  582.      return;
  583.    }
  584.  
  585.    // generic case
  586.    int levelValue = levelGet(index);
  587.    int proto = protoGet(levelValue++);
  588.    protoAdd(proto, levelValue);
  589.  }
  590.  
  591.  private static OffsetKindResult getOffsetKind(Object obj) {
  592.    // starting with Java 21, this would be a nice switch-when.
  593.    if (obj instanceof _Item) {
  594.      return new OffsetKindResult(0, LOCAL);
  595.    }
  596.  
  597.    if (obj == _Ext.INSTANCE || obj instanceof External || obj instanceof String) {
  598.      return new OffsetKindResult(1, EXT);
  599.    }
  600.  
  601.    if (obj == _Include.INSTANCE) {
  602.      return new OffsetKindResult(2, LAMBDA);
  603.    }
  604.  
  605.    // generic case: not implemented
  606.    throw new UnsupportedOperationException(&quot;Implement me :: obj=&quot; + obj);
  607.  }
  608. }&lt;/code&gt;&lt;/pre&gt;
  609. &lt;/div&gt;
  610. &lt;/div&gt;
  611. &lt;/div&gt;
  612. &lt;/div&gt;
  613. &lt;/div&gt;
  614. &lt;div class=&quot;sect1&quot;&gt;
  615. &lt;h2 id=&quot;testing_code_without_else_statements&quot;&gt;Testing code without else statements&lt;/h2&gt;
  616. &lt;div class=&quot;sectionbody&quot;&gt;
  617. &lt;div class=&quot;paragraph&quot;&gt;
  618. &lt;p&gt;Now that we have a few methods with a more restricted responsibility, testing just became easier!
  619. We can open those methods for testing in case you want to cover all the cases.&lt;/p&gt;
  620. &lt;/div&gt;
  621. &lt;div class=&quot;paragraph&quot;&gt;
  622. &lt;p&gt;Here are some tests I came up with.
  623. Please note that they may not be making sense for Objects;
  624. This code is only about showing how easy parts of logic are testable now.&lt;/p&gt;
  625. &lt;/div&gt;
  626. &lt;div class=&quot;listingblock&quot;&gt;
  627. &lt;div class=&quot;content&quot;&gt;
  628. &lt;pre class=&quot;highlightjs highlight&quot;&gt;&lt;code class=&quot;language-java hljs&quot; data-lang=&quot;java&quot;&gt;public class InternalApiTest {
  629.  
  630.  @Test
  631.  public void offsetKind_Item_is_0_local() {
  632.    // given
  633.    Object obj = _Item.INSTANCE;
  634.  
  635.    // when
  636.    OffsetKindResult offsetKind = InternalApi.getOffsetKind(obj);
  637.  
  638.    // then
  639.    assertEquals(offsetKind.offset(), 0);
  640.    assertEquals(offsetKind.kind(), InternalApi.LOCAL);
  641.  }
  642.  
  643.  @Test
  644.  public void throws_exception_on_unknown_object_type() {
  645.    // given
  646.    Object obj = new BigDecimal(0);
  647.  
  648.    // expect
  649.    var unsupportedOperationException = Assert.expectThrows(
  650.        UnsupportedOperationException.class,
  651.        () -&amp;gt; InternalApi.getOffsetKind(obj));
  652.    assertTrue(unsupportedOperationException.getMessage().contains(&quot;Implement me :: obj=&quot;));
  653.  }
  654.  
  655.  @Test
  656.  public void modifyLambda_on_lambda() {
  657.    // given
  658.    var api = new InternalApi();
  659.    var offsetKind = new OffsetKindResult(2, InternalApi.LAMBDA);
  660.  
  661.    // when
  662.    api.modifyLambdaOrProto(offsetKind, 2);
  663.  
  664.    // then
  665.    assertEquals(api.protoArray[0], 0);
  666.    assertEquals(api.protoArray[1], 0);
  667.    assertEquals(api.protoArray[2], 0);
  668.  }
  669. }&lt;/code&gt;&lt;/pre&gt;
  670. &lt;/div&gt;
  671. &lt;/div&gt;
  672. &lt;/div&gt;
  673. &lt;/div&gt;
  674. &lt;div class=&quot;sect1&quot;&gt;
  675. &lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
  676. &lt;div class=&quot;sectionbody&quot;&gt;
  677. &lt;div class=&quot;paragraph&quot;&gt;
  678. &lt;p&gt;In this blog post we discovered how we can avoid &lt;code&gt;else&lt;/code&gt; statements and at the same time gain code clarity and testability.
  679. Please note that applying those rules might not always suit your needs.
  680. However, I found avoiding the &lt;code&gt;else&lt;/code&gt; statement possible and feasible in almost all situations.&lt;/p&gt;
  681. &lt;/div&gt;
  682. &lt;div class=&quot;paragraph&quot;&gt;
  683. &lt;p&gt;Whether to open the extracted methods for testing is your choice.
  684. Especially if they become part of an external API.
  685. But with Java 9+ and JPMS, you can opt out of making public classes available to others.&lt;/p&gt;
  686. &lt;/div&gt;
  687. &lt;div class=&quot;paragraph&quot;&gt;
  688. &lt;p&gt;Given these choices, I find avoiding &lt;code&gt;else&lt;/code&gt; almost always a good idea.&lt;/p&gt;
  689. &lt;/div&gt;
  690. &lt;/div&gt;
  691. &lt;/div&gt;
  692.    </content>
  693.  </entry>
  694.  
  695.  <entry>
  696.    <!-- lang="en-GB"  -->
  697.    <title>Open Liberty: Content negotiation for language output</title>
  698.    <link href="https://blog.bmarwell.de/2023/04/24/open-liberty-user-based-content-language.html"/>
  699.    <id>https://blog.bmarwell.de/2023/04/24/open-liberty-user-based-content-language.html</id>
  700.    <published>2023-04-24T22:07:35Z</published>
  701.    <updated>2023-04-24T22:07:35Z</updated>
  702.    <author>
  703.      <name>Benjamin Marwell</name>
  704.    </author>
  705.    <content type="html">
  706.      &lt;div id=&quot;preamble&quot;&gt;
  707. &lt;div class=&quot;sectionbody&quot;&gt;
  708. &lt;div class=&quot;paragraph&quot;&gt;
  709. &lt;p&gt;Some web applications will want to react to their user‘s browser language.
  710. Here is a short guide on how to do this using a standard JakartaEE restfulWS-based app on &lt;a href=&quot;/tags/OpenLiberty.html&quot;&gt;Open Liberty&lt;/a&gt;.&lt;/p&gt;
  711. &lt;/div&gt;
  712. &lt;/div&gt;
  713. &lt;/div&gt;
  714. &lt;div class=&quot;sect1&quot;&gt;
  715. &lt;h2 id=&quot;step_1_create_a_filter&quot;&gt;Step 1: Create a filter&lt;/h2&gt;
  716. &lt;div class=&quot;sectionbody&quot;&gt;
  717. &lt;div class=&quot;paragraph&quot;&gt;
  718. &lt;p&gt;The first thing you will want to do is to create a filter to save away your user‘s accepted language.
  719. Why a servlet filter?
  720. A filter allows an abstraction from all servlets and controllers.
  721. You would not want to react to the user‘s language individually.&lt;/p&gt;
  722. &lt;/div&gt;
  723. &lt;div class=&quot;paragraph&quot;&gt;
  724. &lt;p&gt;Luckily, the &lt;code&gt;Variant&lt;/code&gt; class is included in JakartaEE.
  725. Here is, how I store the user‘s preferred language in the servlet context:&lt;/p&gt;
  726. &lt;/div&gt;
  727. &lt;div class=&quot;listingblock&quot;&gt;
  728. &lt;div class=&quot;content&quot;&gt;
  729. &lt;pre class=&quot;highlightjs highlight&quot;&gt;&lt;code class=&quot;language-java hljs&quot; data-lang=&quot;java&quot;&gt;import jakarta.ws.rs.container.ContainerRequestContext;
  730. import jakarta.ws.rs.container.ContainerRequestFilter;
  731. import jakarta.ws.rs.container.ContainerResponseContext;
  732. import jakarta.ws.rs.container.ContainerResponseFilter;
  733. import jakarta.ws.rs.core.HttpHeaders;
  734. import jakarta.ws.rs.core.Response;
  735. import jakarta.ws.rs.core.Variant;
  736. import jakarta.ws.rs.ext.Provider;
  737. import java.util.List;
  738. import java.util.Locale;
  739.  
  740. @Provider
  741. public class LanguageFilter implements ContainerRequestFilter, ContainerResponseFilter {
  742.  
  743.    private static final String LANG = &quot;LanguageFilter.lang&quot;;
  744.  
  745.    public static final List&amp;lt;Variant&amp;gt; VARIANTS = Variant.VariantListBuilder.newInstance()
  746.            .languages(Locale.ENGLISH, Locale.GERMAN)
  747.            .build();
  748.  
  749.    @Override
  750.    public void filter(ContainerRequestContext requestContext) {
  751.        Variant variant = requestContext.getRequest().selectVariant(VARIANTS);
  752.  
  753.        if (variant == null) {
  754.            // Error, respond with 406
  755.            requestContext.abortWith(Response.notAcceptable(VARIANTS).build());
  756.        } else {
  757.            // keep the resolved lang around for the response
  758.            requestContext.setProperty(LANG, variant.getLanguageString());
  759.        }
  760.    }
  761.  
  762.    @Override
  763.    public void filter(ContainerRequestContext requestContext, ContainerResponseContext responseContext) {
  764.        String lang = (String) requestContext.getProperty(LANG);
  765.        responseContext.getHeaders().putSingle(HttpHeaders.CONTENT_LANGUAGE, lang);
  766.    }
  767. }&lt;/code&gt;&lt;/pre&gt;
  768. &lt;/div&gt;
  769. &lt;/div&gt;
  770. &lt;div class=&quot;paragraph&quot;&gt;
  771. &lt;p&gt;This filter will extract the preferred language on incoming requests and re-set it (if available) on outgoing requests.&lt;/p&gt;
  772. &lt;/div&gt;
  773. &lt;/div&gt;
  774. &lt;/div&gt;
  775. &lt;div class=&quot;sect1&quot;&gt;
  776. &lt;h2 id=&quot;create_a_message_bundle&quot;&gt;Create a message bundle&lt;/h2&gt;
  777. &lt;div class=&quot;sectionbody&quot;&gt;
  778. &lt;div class=&quot;paragraph&quot;&gt;
  779. &lt;p&gt;Yes, a good old plain Java message bundle!
  780. They are still around and will work for what we want to do here.&lt;/p&gt;
  781. &lt;/div&gt;
  782. &lt;div class=&quot;paragraph&quot;&gt;
  783. &lt;p&gt;Here‘s an example:&lt;/p&gt;
  784. &lt;/div&gt;
  785. &lt;div class=&quot;listingblock&quot;&gt;
  786. &lt;div class=&quot;title&quot;&gt;File &lt;code&gt;de/bmarwell/messages.properties&lt;/code&gt;&lt;/div&gt;
  787. &lt;div class=&quot;content&quot;&gt;
  788. &lt;pre class=&quot;highlightjs highlight&quot;&gt;&lt;code class=&quot;language-properties hljs&quot; data-lang=&quot;properties&quot;&gt;help.generic = Welcome to the dice parser!&lt;/code&gt;&lt;/pre&gt;
  789. &lt;/div&gt;
  790. &lt;/div&gt;
  791. &lt;div class=&quot;listingblock&quot;&gt;
  792. &lt;div class=&quot;title&quot;&gt;File &lt;code&gt;de/bmarwell/messages_de.properties&lt;/code&gt;&lt;/div&gt;
  793. &lt;div class=&quot;content&quot;&gt;
  794. &lt;pre class=&quot;highlightjs highlight&quot;&gt;&lt;code class=&quot;language-properties hljs&quot; data-lang=&quot;properties&quot;&gt;help.generic = Willkommen beim Würfel-Parser!&lt;/code&gt;&lt;/pre&gt;
  795. &lt;/div&gt;
  796. &lt;/div&gt;
  797. &lt;/div&gt;
  798. &lt;/div&gt;
  799. &lt;div class=&quot;sect1&quot;&gt;
  800. &lt;h2 id=&quot;create_an_injectable_messageprovider_cdi_bean&quot;&gt;Create an injectable MessageProvider CDI bean&lt;/h2&gt;
  801. &lt;div class=&quot;sectionbody&quot;&gt;
  802. &lt;div class=&quot;paragraph&quot;&gt;
  803. &lt;p&gt;To be able to use a single message provider, you can use this class:&lt;/p&gt;
  804. &lt;/div&gt;
  805. &lt;div class=&quot;listingblock&quot;&gt;
  806. &lt;div class=&quot;content&quot;&gt;
  807. &lt;pre class=&quot;highlightjs highlight&quot;&gt;&lt;code class=&quot;language-java hljs&quot; data-lang=&quot;java&quot;&gt;import jakarta.enterprise.context.ApplicationScoped;
  808. import java.io.Serial;
  809. import java.util.Locale;
  810. import java.util.Map;
  811. import java.util.MissingResourceException;
  812. import java.util.Optional;
  813. import java.util.ResourceBundle;
  814. import java.util.concurrent.ConcurrentHashMap;
  815.  
  816. @ApplicationScoped
  817. public class ResourceBundleMessageProvider implements MessageProvider {
  818.  
  819.    @Override
  820.    public String getString(String bundleName, Locale locale, String helpKey) {
  821.        try {
  822.            final ResourceBundle resourceBundle = ResourceBundle.getBundle(bundleName, locale);
  823.            return resourceBundle.getString(helpKey);
  824.        } catch (MissingResourceException missingResourceException) {
  825.            return &quot;&quot;;
  826.        }
  827.    }
  828. }&lt;/code&gt;&lt;/pre&gt;
  829. &lt;/div&gt;
  830. &lt;/div&gt;
  831. &lt;div class=&quot;paragraph&quot;&gt;
  832. &lt;p&gt;Of course this needs some heave tweaking before such a class could go into production.
  833. Defaults, anyone?
  834. But for the sake of showing how to react to preferred languages, this will do for now.&lt;/p&gt;
  835. &lt;/div&gt;
  836. &lt;/div&gt;
  837. &lt;/div&gt;
  838. &lt;div class=&quot;sect1&quot;&gt;
  839. &lt;h2 id=&quot;load_messages&quot;&gt;Load messages&lt;/h2&gt;
  840. &lt;div class=&quot;sectionbody&quot;&gt;
  841. &lt;div class=&quot;paragraph&quot;&gt;
  842. &lt;p&gt;Now with resources and a CDI bean at hand, you can load the localized strings wherever you like:&lt;/p&gt;
  843. &lt;/div&gt;
  844. &lt;div class=&quot;listingblock&quot;&gt;
  845. &lt;div class=&quot;content&quot;&gt;
  846. &lt;pre class=&quot;highlightjs highlight&quot;&gt;&lt;code class=&quot;language-java hljs&quot; data-lang=&quot;java&quot;&gt;import jakarta.enterprise.context.ApplicationScoped;
  847. import jakarta.inject.Inject;
  848. import jakarta.ws.rs.GET;
  849. import jakarta.ws.rs.Path;
  850. import jakarta.ws.rs.Produces;
  851. import jakarta.ws.rs.core.Context;
  852. import jakarta.ws.rs.core.MediaType;
  853. import jakarta.ws.rs.core.Request;
  854. import jakarta.ws.rs.core.UriInfo;
  855.  
  856. @Path(&quot;/&quot;)
  857. @ApplicationScoped
  858. public class HelpResource {
  859.  
  860.    @Inject
  861.    private MessageProvider msgProvider;
  862.  
  863.    @GET
  864.    @Produces(MediaType.TEXT_PLAIN)
  865.    public String help(@Context Request request, @Context UriInfo uriInfo) {
  866.        return msgProvider.getString(
  867.              &quot;messages&quot;,
  868.              request.selectVariant(LanguageFilter.VARIANTS).getLanguage(),
  869.              &quot;help.generic&quot;
  870.        );
  871.    }
  872.  
  873. }&lt;/code&gt;&lt;/pre&gt;
  874. &lt;/div&gt;
  875. &lt;/div&gt;
  876. &lt;/div&gt;
  877. &lt;/div&gt;
  878. &lt;div class=&quot;sect1&quot;&gt;
  879. &lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
  880. &lt;div class=&quot;sectionbody&quot;&gt;
  881. &lt;div class=&quot;paragraph&quot;&gt;
  882. &lt;p&gt;It is easy to get started with localized applications.
  883. Just be sure to extend on the idea, as this is not production ready.&lt;/p&gt;
  884. &lt;/div&gt;
  885. &lt;div class=&quot;paragraph&quot;&gt;
  886. &lt;p&gt;More features you might want to see in your application are:&lt;/p&gt;
  887. &lt;/div&gt;
  888. &lt;div class=&quot;ulist&quot;&gt;
  889. &lt;ul&gt;
  890. &lt;li&gt;
  891. &lt;p&gt;react to user agents differently.&lt;/p&gt;
  892. &lt;/li&gt;
  893. &lt;li&gt;
  894. &lt;p&gt;the same language, but different countries.&lt;/p&gt;
  895. &lt;/li&gt;
  896. &lt;li&gt;
  897. &lt;p&gt;format strings with placeholders like &lt;code&gt;%s&lt;/code&gt;.&lt;/p&gt;
  898. &lt;/li&gt;
  899. &lt;/ul&gt;
  900. &lt;/div&gt;
  901. &lt;div class=&quot;paragraph&quot;&gt;
  902. &lt;p&gt;However, JAX-RS or RestfulWS will already have prepopulated the &lt;code&gt;variant&lt;/code&gt; http header for your.
  903. Neat!&lt;/p&gt;
  904. &lt;/div&gt;
  905. &lt;/div&gt;
  906. &lt;/div&gt;
  907.    </content>
  908.  </entry>
  909.  
  910.  <entry>
  911.    <!-- lang="en-GB"  -->
  912.    <title>The best alternative to <code>Thread.sleep()</code> in Java</title>
  913.    <link href="https://blog.bmarwell.de/2023/04/23/the-best-alternative-to-thread-sleep-in-java.html"/>
  914.    <id>https://blog.bmarwell.de/2023/04/23/the-best-alternative-to-thread-sleep-in-java.html</id>
  915.    <published>2023-04-23T22:19:14Z</published>
  916.    <updated>2023-04-23T22:32:14Z</updated>
  917.    <author>
  918.      <name>Benjamin Marwell</name>
  919.    </author>
  920.    <content type="html">
  921.      &lt;div id=&quot;preamble&quot;&gt;
  922. &lt;div class=&quot;sectionbody&quot;&gt;
  923. &lt;div class=&quot;paragraph&quot;&gt;
  924. &lt;p&gt;In case you use &lt;code&gt;Thread.sleep()&lt;/code&gt; in either your Java code or your unit tests, &lt;a href=&quot;https://www.objectos.com.br/blog/alternative-thread-sleep-in-your-java-tests.html&quot;&gt;an article by Marcio Endo has you covered&lt;/a&gt;.
  925. However, I think two alternatives are really worth mentioning.&lt;/p&gt;
  926. &lt;/div&gt;
  927. &lt;/div&gt;
  928. &lt;/div&gt;
  929. &lt;div class=&quot;sect1&quot;&gt;
  930. &lt;h2 id=&quot;alternatives_introduction_avoid_thread_sleep_in_your_java_code&quot;&gt;Alternatives introduction: avoid Thread.sleep in your Java code&lt;/h2&gt;
  931. &lt;div class=&quot;sectionbody&quot;&gt;
  932. &lt;div class=&quot;paragraph&quot;&gt;
  933. &lt;p&gt;Well, in Marcio‘s examples, you had to modify your original Java code to make things work.
  934. I do not think you should be needing to modify your Java code just for the sake of tests&amp;#8201;&amp;#8212;&amp;#8201;only adding getters and setters (preferrably protected) should be needed.
  935. That said, let‘s look again at the original class:&lt;/p&gt;
  936. &lt;/div&gt;
  937. &lt;script src=&quot;https://gist.github.com/bmarwell/d01d66f7637deadf6e5c97719c61f69a.js&quot;&gt;&lt;/script&gt;
  938. &lt;/div&gt;
  939. &lt;/div&gt;
  940. &lt;div class=&quot;sect1&quot;&gt;
  941. &lt;h2 id=&quot;no_alternative_using_timeunit_instead_of_thread_sleep&quot;&gt;No alternative: Using TimeUnit instead of Thread.sleep()&lt;/h2&gt;
  942. &lt;div class=&quot;sectionbody&quot;&gt;
  943. &lt;div class=&quot;paragraph&quot;&gt;
  944. &lt;p&gt;Instead of using &lt;code&gt;Thread.sleep(1000)&lt;/code&gt; in your tests, you could just use a simpler API: &lt;a href=&quot;https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/TimeUnit.html#sleep(long)&quot;&gt;&lt;code&gt;TimeUnit#sleep(long timeout)&lt;/code&gt;&lt;/a&gt;:&lt;/p&gt;
  945. &lt;/div&gt;
  946. &lt;div class=&quot;listingblock&quot;&gt;
  947. &lt;div class=&quot;content&quot;&gt;
  948. &lt;pre class=&quot;highlightjs highlight&quot;&gt;&lt;code class=&quot;language-java hljs&quot; data-lang=&quot;java&quot;&gt;try {
  949.  TimeUnit.MILLISECONDS.sleep(1000);
  950. } catch (InterruptedException intEx) {
  951.  // handle... log or rethrow
  952. }&lt;/code&gt;&lt;/pre&gt;
  953. &lt;/div&gt;
  954. &lt;/div&gt;
  955. &lt;div class=&quot;paragraph&quot;&gt;
  956. &lt;p&gt;As you can see, you will still have to deal with all the Exception handling and you will have to create a while loop around it.
  957. That said, this is not a viable alternative to &lt;code&gt;Thread.sleep()&lt;/code&gt; except it might be a little easier to read.&lt;/p&gt;
  958. &lt;/div&gt;
  959. &lt;/div&gt;
  960. &lt;/div&gt;
  961. &lt;div class=&quot;sect1&quot;&gt;
  962. &lt;h2 id=&quot;alternative_1_use_awaitility_for_tests&quot;&gt;Alternative 1: Use awaitility for tests&lt;/h2&gt;
  963. &lt;div class=&quot;sectionbody&quot;&gt;
  964. &lt;div class=&quot;paragraph&quot;&gt;
  965. &lt;p&gt;If you only needed the timeout in your JUnit test, you might not want to heavily alter your class for no reason than just testing.
  966. Given this premise, there is a nice utility which can help you with this: &lt;a href=&quot;http://www.awaitility.org&quot;&gt;awaitility&lt;/a&gt;.&lt;/p&gt;
  967. &lt;/div&gt;
  968. &lt;div class=&quot;paragraph&quot;&gt;
  969. &lt;p&gt;Here is a complete test class:&lt;/p&gt;
  970. &lt;/div&gt;
  971. &lt;script src=&quot;https://gist.github.com/bmarwell/c5f9a1358297316169cd86cbc4461a33.js&quot;&gt;&lt;/script&gt;
  972. &lt;div class=&quot;paragraph&quot;&gt;
  973. &lt;p&gt;This will return 22(ms).&lt;/p&gt;
  974. &lt;/div&gt;
  975. &lt;div class=&quot;paragraph&quot;&gt;
  976. &lt;p&gt;The neat thing about this solution is that you do not need to do anything about threading.
  977. It also supports both Duration and long plus &lt;code&gt;TimeUnit&lt;/code&gt; in its APIs.
  978. Usually, you do not need to set &lt;code&gt;pollInterval()&lt;/code&gt;.
  979. I only did it because the default seems to be 100ms to get a somewhat more realistic value.&lt;/p&gt;
  980. &lt;/div&gt;
  981. &lt;div class=&quot;paragraph&quot;&gt;
  982. &lt;p&gt;This is a very tiny dependency with an easy-to-understand API.
  983. I use it a lot in Maven modules where I do threading and async operations.&lt;/p&gt;
  984. &lt;/div&gt;
  985. &lt;div class=&quot;paragraph&quot;&gt;
  986. &lt;p&gt;If you start the thread using a &lt;code&gt;CompletableFuture&lt;/code&gt;, you can get entirely rid of the thread management in the counter class.
  987. This is recommended, as it is not the Counter class‘s responsibility to deal with threads.&lt;/p&gt;
  988. &lt;/div&gt;
  989. &lt;div class=&quot;paragraph&quot;&gt;
  990. &lt;p&gt;Another advantage to TestNG is, that you do not set a global test method timeout, but instead a timeout for each logical unit.&lt;/p&gt;
  991. &lt;/div&gt;
  992. &lt;/div&gt;
  993. &lt;/div&gt;
  994. &lt;div class=&quot;sect1&quot;&gt;
  995. &lt;h2 id=&quot;alternative_2_using_completablefutures&quot;&gt;Alternative 2: Using CompletableFutures&lt;/h2&gt;
  996. &lt;div class=&quot;sectionbody&quot;&gt;
  997. &lt;div class=&quot;paragraph&quot;&gt;
  998. &lt;p&gt;If you need to time out some background operation in your production code, you can use the &lt;code&gt;java.concurrent&lt;/code&gt; API.
  999. This API is also available in JakartaEE, whith only one tiny caveat&amp;#8201;&amp;#8212;&amp;#8201; luckily, it is easy to remember.&lt;/p&gt;
  1000. &lt;/div&gt;
  1001. &lt;div class=&quot;sect2&quot;&gt;
  1002. &lt;h3 id=&quot;using_in_any_javase_application&quot;&gt;Using in any JavaSE application&lt;/h3&gt;
  1003. &lt;script src=&quot;https://gist.github.com/bmarwell/301eae6c1ce8ffa74cc0e995d36b74e4.js&quot;&gt;&lt;/script&gt;
  1004. &lt;div class=&quot;paragraph&quot;&gt;
  1005. &lt;p&gt;This will return 33(ms) on my machine.&lt;/p&gt;
  1006. &lt;/div&gt;
  1007. &lt;div class=&quot;paragraph&quot;&gt;
  1008. &lt;p&gt;As we are using streams, it is easy to extend from here by using a second &lt;code&gt;CompletableFuture&lt;/code&gt; (maybe a completed one) as a fallback.
  1009. That way we would not need to specify a default after the &lt;code&gt;findFirst()&lt;/code&gt; method.&lt;/p&gt;
  1010. &lt;/div&gt;
  1011. &lt;/div&gt;
  1012. &lt;div class=&quot;sect2&quot;&gt;
  1013. &lt;h3 id=&quot;using_in_a_jakartaee_web_application&quot;&gt;Using in a JakartaEE web application&lt;/h3&gt;
  1014. &lt;div class=&quot;paragraph&quot;&gt;
  1015. &lt;p&gt;Web applications are not allowed to start threads on their own.
  1016. Instead, just inject a &lt;code&gt;ManagedExecutorService&lt;/code&gt; as a field and add it as a second parameter to the &lt;code&gt;CompletableFuture#supplyAsync()&lt;/code&gt;.
  1017. That‘s all there is to it!&lt;/p&gt;
  1018. &lt;/div&gt;
  1019. &lt;/div&gt;
  1020. &lt;/div&gt;
  1021. &lt;/div&gt;
  1022. &lt;div class=&quot;sect1&quot;&gt;
  1023. &lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
  1024. &lt;div class=&quot;sectionbody&quot;&gt;
  1025. &lt;div class=&quot;paragraph&quot;&gt;
  1026. &lt;p&gt;The best alternative to using &lt;code&gt;Thread.sleep()&lt;/code&gt; in Java is to avoid it by using either the awaitility library for your tests or using the &lt;code&gt;java.concurrent&lt;/code&gt; API in your programme code.&lt;/p&gt;
  1027. &lt;/div&gt;
  1028. &lt;/div&gt;
  1029. &lt;/div&gt;
  1030.    </content>
  1031.  </entry>
  1032.  
  1033.  <entry>
  1034.    <!-- lang="de-DE"  -->
  1035.    <title>Die beste Alternative zu <code>Thread.sleep()</code> in Java</title>
  1036.    <link href="https://blog.bmarwell.de/2023/04/23/die-beste-alternative-zu-thread-sleep-in-java.html"/>
  1037.    <id>https://blog.bmarwell.de/2023/04/23/die-beste-alternative-zu-thread-sleep-in-java.html</id>
  1038.    <published>2023-04-23T22:19:14Z</published>
  1039.    <updated>2023-04-23T22:32:14Z</updated>
  1040.    <author>
  1041.      <name>Benjamin Marwell</name>
  1042.    </author>
  1043.    <content type="html">
  1044.      &lt;div id=&quot;preamble&quot;&gt;
  1045. &lt;div class=&quot;sectionbody&quot;&gt;
  1046. &lt;div class=&quot;paragraph&quot;&gt;
  1047. &lt;p&gt;Falls Du &lt;code&gt;Thread.sleep()&lt;/code&gt; entweder in Deinem Java-Code or Unit-Test verewndest, &lt;a href=&quot;https://www.objectos.com.br/blog/alternative-thread-sleep-in-your-java-tests.html&quot;&gt;gibt ein Artikel von Marcio Endo wertvolle Tipps&lt;/a&gt;.
  1048. Allerdings denke ich, dass es zwei sinnvolle Alternativen zu seinen Vorschlägen gibt.&lt;/p&gt;
  1049. &lt;/div&gt;
  1050. &lt;/div&gt;
  1051. &lt;/div&gt;
  1052. &lt;div class=&quot;sect1&quot;&gt;
  1053. &lt;h2 id=&quot;einleitung_vermeide_thread_sleep_im_java_code&quot;&gt;Einleitung: vermeide Thread.sleep im Java-Code&lt;/h2&gt;
  1054. &lt;div class=&quot;sectionbody&quot;&gt;
  1055. &lt;div class=&quot;paragraph&quot;&gt;
  1056. &lt;p&gt;In Marcios Beispiel musste man an der Originalklasse Änderungen vornehmen, um die Lauffähigkeit der Tests herzustellen.
  1057. Meiner Meinung nach sollte man Produktions-Code nicht für Tests anpassen müssen&amp;#8201;&amp;#8212;&amp;#8201;außer, er ist schlecht geschrieben oder man fügt lediglich getter und setter (vorzugsweise protected) ein.
  1058. Mit dieser These im Hinterkopf, lasst uns nochmal die Original-Klasse vor Augen führen:&lt;/p&gt;
  1059. &lt;/div&gt;
  1060. &lt;script src=&quot;https://gist.github.com/bmarwell/d01d66f7637deadf6e5c97719c61f69a.js&quot;&gt;&lt;/script&gt;
  1061. &lt;/div&gt;
  1062. &lt;/div&gt;
  1063. &lt;div class=&quot;sect1&quot;&gt;
  1064. &lt;h2 id=&quot;keine_alternative_timeunit_statt_thread_sleep&quot;&gt;Keine Alternative: TimeUnit statt Thread.sleep()&lt;/h2&gt;
  1065. &lt;div class=&quot;sectionbody&quot;&gt;
  1066. &lt;div class=&quot;paragraph&quot;&gt;
  1067. &lt;p&gt;Statt &lt;code&gt;Thread.sleep(1000)&lt;/code&gt; in den Tests zu nutzen, kann man natürlich auch einfach diese einfachere API nutzen: &lt;a href=&quot;https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/TimeUnit.html#sleep(long)&quot;&gt;&lt;code&gt;TimeUnit#sleep(long timeout)&lt;/code&gt;&lt;/a&gt;:&lt;/p&gt;
  1068. &lt;/div&gt;
  1069. &lt;div class=&quot;listingblock&quot;&gt;
  1070. &lt;div class=&quot;content&quot;&gt;
  1071. &lt;pre class=&quot;highlightjs highlight&quot;&gt;&lt;code class=&quot;language-java hljs&quot; data-lang=&quot;java&quot;&gt;try {
  1072.  TimeUnit.MILLISECONDS.sleep(1000);
  1073. } catch (InterruptedException intEx) {
  1074.  // handle... log or rethrow
  1075. }&lt;/code&gt;&lt;/pre&gt;
  1076. &lt;/div&gt;
  1077. &lt;/div&gt;
  1078. &lt;div class=&quot;paragraph&quot;&gt;
  1079. &lt;p&gt;Wie man aber sieht, muss man sich immer noch um das Exception-Handling kümmern und eine While-Schleife drum herum schreiben.
  1080. Daher ist diese Methode kein Fortschritt gegenüber &lt;code&gt;Thread.sleep()&lt;/code&gt;, sieht man einmal davon ab, dass sie bei größeren Timeouts minimal leichter zu lesen ist.&lt;/p&gt;
  1081. &lt;/div&gt;
  1082. &lt;/div&gt;
  1083. &lt;/div&gt;
  1084. &lt;div class=&quot;sect1&quot;&gt;
  1085. &lt;h2 id=&quot;alternative_1_awaitility_für_tests_nutzen&quot;&gt;Alternative 1: Awaitility für Tests nutzen&lt;/h2&gt;
  1086. &lt;div class=&quot;sectionbody&quot;&gt;
  1087. &lt;div class=&quot;paragraph&quot;&gt;
  1088. &lt;p&gt;Wenn man den Timeout nur im JUnit-Test benötigt, möchte man wie gesagt nicht extra seine bestehenden Klassen wesentlich anpassen.
  1089. Mit dieser Vorraussetzung im Hinterkopf kann man auf ein kleines Tool (eine Library) ausweichen, die diese Logik im Test für einen übernimmt: &lt;a href=&quot;http://www.awaitility.org&quot;&gt;awaitility&lt;/a&gt;.&lt;/p&gt;
  1090. &lt;/div&gt;
  1091. &lt;div class=&quot;paragraph&quot;&gt;
  1092. &lt;p&gt;Das hier ist der vollständige JUnit-Test:&lt;/p&gt;
  1093. &lt;/div&gt;
  1094. &lt;script src=&quot;https://gist.github.com/bmarwell/c5f9a1358297316169cd86cbc4461a33.js&quot;&gt;&lt;/script&gt;
  1095. &lt;div class=&quot;paragraph&quot;&gt;
  1096. &lt;p&gt;Die Ausgabe ist: 22(ms).&lt;/p&gt;
  1097. &lt;/div&gt;
  1098. &lt;div class=&quot;paragraph&quot;&gt;
  1099. &lt;p&gt;Das schöne an dieser Lösung ist, dass man sich um Threading gar nicht kümmern muss.
  1100. Außerdem unterstützt Awaitility in seinen APIs immer beide Aufrufe: Die Angabe von &lt;code&gt;Duration&lt;/code&gt; sowie eine Methodensignatur mit long und &lt;code&gt;TimeUnit&lt;/code&gt;.&lt;/p&gt;
  1101. &lt;/div&gt;
  1102. &lt;div class=&quot;paragraph&quot;&gt;
  1103. &lt;p&gt;Die Methode &lt;code&gt;pollInterval()&lt;/code&gt; habe ich daher auch nur für dieses Beispiel benutzt.
  1104. Zum einen sieht man hier die andere API, zum Anderen kommt man an etwas realistischere Werte: Der Default liegt vermutlich eher bei 100ms.&lt;/p&gt;
  1105. &lt;/div&gt;
  1106. &lt;div class=&quot;paragraph&quot;&gt;
  1107. &lt;p&gt;Diese winzige Maven-Dependency ist zudem sehr einfach verständlich.
  1108. Ich nutze Awaitlity sehr oft in Maven-Modulen zum Testen, wenn ich in diesen Modulen auch async-Calls und Threading verwende.&lt;/p&gt;
  1109. &lt;/div&gt;
  1110. &lt;div class=&quot;paragraph&quot;&gt;
  1111. &lt;p&gt;Startet man den Thread darüber hinaus mit &lt;code&gt;CompletableFuture&lt;/code&gt;, kann man die Thread-Management-Methode komplett aus dem Counter entfernen.
  1112. Das kann ich nur empfehlen, da Thread-Management nicht in der Verantwortlichkeit einer Counter-Klasse liegen sollte.&lt;/p&gt;
  1113. &lt;/div&gt;
  1114. &lt;/div&gt;
  1115. &lt;/div&gt;
  1116. &lt;div class=&quot;sect1&quot;&gt;
  1117. &lt;h2 id=&quot;alternative_2_completablefutures_nutzen&quot;&gt;Alternative 2: CompletableFutures nutzen&lt;/h2&gt;
  1118. &lt;div class=&quot;sectionbody&quot;&gt;
  1119. &lt;div class=&quot;paragraph&quot;&gt;
  1120. &lt;p&gt;Wenn man aber im Produktions-Code mit Hintergrund-Operationen arbeitet, dann kann man bestehende Funktionalität aus der &lt;code&gt;java.concurrent&lt;/code&gt;-API nehmen.
  1121. Diese API ist prinzipiell auch in JakartaEE verfügbar, mit nur einer einzigen Anpassung&amp;#8201;&amp;#8212;&amp;#8201;und diese ist zum Glück auch einfach in Erinnerung zu behalten.&lt;/p&gt;
  1122. &lt;/div&gt;
  1123. &lt;div class=&quot;sect2&quot;&gt;
  1124. &lt;h3 id=&quot;completablefuture_in_einer_javase_anwendung&quot;&gt;CompletableFuture in einer JavaSE-Anwendung&lt;/h3&gt;
  1125. &lt;script src=&quot;https://gist.github.com/bmarwell/301eae6c1ce8ffa74cc0e995d36b74e4.js&quot;&gt;&lt;/script&gt;
  1126. &lt;div class=&quot;paragraph&quot;&gt;
  1127. &lt;p&gt;Dieser Code gibt 33(ms) auf meinem Laptop aus.&lt;/p&gt;
  1128. &lt;/div&gt;
  1129. &lt;div class=&quot;paragraph&quot;&gt;
  1130. &lt;p&gt;Da wir Streams nutzen, ist hier der große Vorteil vorhanden, dass wir die Logik sehr einfach anpassen können.
  1131. Man könnte etwa ein (completed) &lt;code&gt;CompletableFuture&lt;/code&gt; als Fallback mit hinzufügen, um am Ende auf das Default hinter der &lt;code&gt;.findFirst()&lt;/code&gt;-Methode verzichten zu können.&lt;/p&gt;
  1132. &lt;/div&gt;
  1133. &lt;/div&gt;
  1134. &lt;div class=&quot;sect2&quot;&gt;
  1135. &lt;h3 id=&quot;completablefutures_in_einer_jakartaee_web_anwendung&quot;&gt;CompletableFutures in einer JakartaEE Web-Anwendung&lt;/h3&gt;
  1136. &lt;div class=&quot;paragraph&quot;&gt;
  1137. &lt;p&gt;Web-Anwendungen dürfen keine eigenen Threads starten, so steht es in der Spezifikation.
  1138. Stattdessen muss man sich einen &lt;code&gt;ManagedExecutorService&lt;/code&gt; als Feld injizieren lassen.
  1139. Dieses übergibt man als zweiten Parameter an  &lt;code&gt;CompletableFuture#supplyAsync()&lt;/code&gt;.
  1140. Das ist alles, was man beachten muss!&lt;/p&gt;
  1141. &lt;/div&gt;
  1142. &lt;/div&gt;
  1143. &lt;/div&gt;
  1144. &lt;/div&gt;
  1145. &lt;div class=&quot;sect1&quot;&gt;
  1146. &lt;h2 id=&quot;fazit&quot;&gt;Fazit&lt;/h2&gt;
  1147. &lt;div class=&quot;sectionbody&quot;&gt;
  1148. &lt;div class=&quot;paragraph&quot;&gt;
  1149. &lt;p&gt;Die beste alternative zu &lt;code&gt;Thread.sleep()&lt;/code&gt; in Java ist die Vermeidung durch die Nutzung von entweder Awaitility in tests oder durch die Nutzung der &lt;code&gt;java.concurrent&lt;/code&gt;-API in Produktions-Code.&lt;/p&gt;
  1150. &lt;/div&gt;
  1151. &lt;/div&gt;
  1152. &lt;/div&gt;
  1153.    </content>
  1154.  </entry>
  1155.  
  1156.  <entry>
  1157.    <!-- lang="en-GB"  -->
  1158.    <title>JSON-B <code>@JsonbConstructor</code> bug: Property Naming Strategy not applied</title>
  1159.    <link href="https://blog.bmarwell.de/2022/12/09/jsonbconstructor_bug_naming_strategy.html"/>
  1160.    <id>https://blog.bmarwell.de/2022/12/09/jsonbconstructor_bug_naming_strategy.html</id>
  1161.    <published>2022-12-09T06:00:35Z</published>
  1162.    <updated>2022-12-09T06:40:35Z</updated>
  1163.    <author>
  1164.      <name>Benjamin Marwell</name>
  1165.    </author>
  1166.    <content type="html">
  1167.      &lt;div id=&quot;preamble&quot;&gt;
  1168. &lt;div class=&quot;sectionbody&quot;&gt;
  1169. &lt;div class=&quot;paragraph&quot;&gt;
  1170. &lt;p&gt;A long-standig bug in JakartaEE’s JSON-B implementations (JSON Binding) cause me some headaches.
  1171. Luckily, I was able to track it down.
  1172. Here is how to reproduce it and why you might hit it sooner rather than later.&lt;/p&gt;
  1173. &lt;/div&gt;
  1174. &lt;div class=&quot;paragraph&quot;&gt;
  1175. &lt;p&gt;In short: The Property Naming Strategy is not applied to Java Records containing a &lt;code&gt;@JsonbConstructor&lt;/code&gt; annotation.
  1176. This bug exists in both implementations, Apache Johnzon and Eclipse Yasson.&lt;/p&gt;
  1177. &lt;/div&gt;
  1178. &lt;/div&gt;
  1179. &lt;/div&gt;
  1180. &lt;div class=&quot;sect1&quot;&gt;
  1181. &lt;h2 id=&quot;propertyvisibilitystrategy_java_17_records&quot;&gt;PropertyVisibilityStrategy: Java 17 Records&lt;/h2&gt;
  1182. &lt;div class=&quot;sectionbody&quot;&gt;
  1183. &lt;div class=&quot;paragraph&quot;&gt;
  1184. &lt;p&gt;To (de)serialize records, you need to modify the &lt;code&gt;PropertyVisibilityStrategy&lt;/code&gt;.
  1185. This strategy defines how properties, which should get (de-)serialized should be discovered by the JSON-B implementation.
  1186. Because JSON-B implementations are made for Java beans (getters and setters), and Java Records broke this pattern by omitting the &lt;code&gt;get…()&lt;/code&gt; in the method names, you first need to define a Visibility Strategy which picks up those internal properties:&lt;/p&gt;
  1187. &lt;/div&gt;
  1188. &lt;div class=&quot;listingblock&quot;&gt;
  1189. &lt;div class=&quot;title&quot;&gt;JSON-B VisibilityStrategy for Java Records&lt;/div&gt;
  1190. &lt;div class=&quot;content&quot;&gt;
  1191. &lt;pre class=&quot;highlightjs highlight&quot;&gt;&lt;code class=&quot;language-java hljs&quot; data-lang=&quot;java&quot;&gt;static class PrivateVisibilityStrategy implements PropertyVisibilityStrategy {
  1192.    @Override
  1193.    public boolean isVisible(Field field) { return true; }
  1194.    @Override
  1195.    public boolean isVisible(Method method) { return false; }
  1196. }&lt;/code&gt;&lt;/pre&gt;
  1197. &lt;/div&gt;
  1198. &lt;/div&gt;
  1199. &lt;div class=&quot;paragraph&quot;&gt;
  1200. &lt;p&gt;Serialization will work now.
  1201. For an imaginary &lt;code&gt;record Person&lt;/code&gt;:&lt;/p&gt;
  1202. &lt;/div&gt;
  1203. &lt;div class=&quot;listingblock&quot;&gt;
  1204. &lt;div class=&quot;content&quot;&gt;
  1205. &lt;pre class=&quot;highlightjs highlight&quot;&gt;&lt;code class=&quot;language-json hljs&quot; data-lang=&quot;json&quot;&gt;{
  1206.  &quot;firstName&quot;: &quot;Richard&quot;,
  1207.  &quot;lastName&quot;: &quot;Feynman&quot;
  1208. }&lt;/code&gt;&lt;/pre&gt;
  1209. &lt;/div&gt;
  1210. &lt;/div&gt;
  1211. &lt;/div&gt;
  1212. &lt;/div&gt;
  1213. &lt;div class=&quot;sect1&quot;&gt;
  1214. &lt;h2 id=&quot;add_propertynamingstrategy_into_the_mix&quot;&gt;Add PropertyNamingStrategy into the mix&lt;/h2&gt;
  1215. &lt;div class=&quot;sectionbody&quot;&gt;
  1216. &lt;div class=&quot;paragraph&quot;&gt;
  1217. &lt;p&gt;Now, think of all your &lt;code&gt;lowerCamelCase&lt;/code&gt; methods (and properties): Those are not too typical for JSON.
  1218. In fact, most JSON you encounter written in Python or PHP or JavaScript or TypeScript will instead use &lt;code&gt;lower_snake_case&lt;/code&gt; for property naming.
  1219. To »comply« with this de-factor standard, you can make JSON-B implementations rename and map your JSON-B field names accordingly:&lt;/p&gt;
  1220. &lt;/div&gt;
  1221. &lt;div class=&quot;listingblock&quot;&gt;
  1222. &lt;div class=&quot;title&quot;&gt;JSON-B PropertyNamingStrategy for lower_snake_case&lt;/div&gt;
  1223. &lt;div class=&quot;content&quot;&gt;
  1224. &lt;pre class=&quot;highlightjs highlight&quot;&gt;&lt;code class=&quot;language-java hljs&quot; data-lang=&quot;java&quot;&gt;new JsonbConfig()
  1225.    .withNullValues(Boolean.TRUE)
  1226.    .withFormatting(Boolean.TRUE)
  1227.    .withPropertyVisibilityStrategy(new PrivateVisibilityStrategy())
  1228.    .withPropertyNamingStrategy(PropertyNamingStrategy.LOWER_CASE_WITH_UNDERSCORES)
  1229.    ;&lt;/code&gt;&lt;/pre&gt;
  1230. &lt;/div&gt;
  1231. &lt;/div&gt;
  1232. &lt;div class=&quot;paragraph&quot;&gt;
  1233. &lt;p&gt;The last line calls the built-in &lt;code&gt;LOWER_CASE_WITH_UNDERSCORES&lt;/code&gt; which every JSON-B implementation must support.&lt;/p&gt;
  1234. &lt;/div&gt;
  1235. &lt;div class=&quot;paragraph&quot;&gt;
  1236. &lt;p&gt;Now you properties will be serialized like this:&lt;/p&gt;
  1237. &lt;/div&gt;
  1238. &lt;div class=&quot;listingblock&quot;&gt;
  1239. &lt;div class=&quot;content&quot;&gt;
  1240. &lt;pre class=&quot;highlightjs highlight&quot;&gt;&lt;code class=&quot;language-json hljs&quot; data-lang=&quot;json&quot;&gt;{
  1241.  &quot;first_name&quot;: &quot;Richard&quot;,
  1242.  &quot;last_name&quot;: &quot;Feynman&quot;
  1243. }&lt;/code&gt;&lt;/pre&gt;
  1244. &lt;/div&gt;
  1245. &lt;/div&gt;
  1246. &lt;/div&gt;
  1247. &lt;/div&gt;
  1248. &lt;div class=&quot;sect1&quot;&gt;
  1249. &lt;h2 id=&quot;deserializing_with_jsonbconstructor&quot;&gt;Deserializing with &lt;code&gt;@JsonbConstructor&lt;/code&gt;&lt;/h2&gt;
  1250. &lt;div class=&quot;sectionbody&quot;&gt;
  1251. &lt;div class=&quot;paragraph&quot;&gt;
  1252. &lt;p&gt;Now the funny part: Deserializing.
  1253. By default, JSON-B implementations won’t be able to do that: They need a non-private no-arg-constructor, which just is not available with Records.
  1254. An alternative to this is either a static factory method OR an annotated constructor.
  1255. While both could work for records, there is a neat trick: Records in Java can be written with a no-arg-constructor, which is called with all the fields.
  1256. That’s a little bit of magic there, but it works just fine.
  1257. So the following class &lt;strong&gt;should&lt;/strong&gt; work:&lt;/p&gt;
  1258. &lt;/div&gt;
  1259. &lt;div class=&quot;listingblock&quot;&gt;
  1260. &lt;div class=&quot;content&quot;&gt;
  1261. &lt;pre class=&quot;highlightjs highlight&quot;&gt;&lt;code class=&quot;language-java hljs&quot; data-lang=&quot;java&quot;&gt;public record Person(String firstName, String lastName) {
  1262.  @JsonbCreator
  1263.  public Author {
  1264.    requireNonNull(firstName, &quot;firstName&quot;);
  1265.    requireNonNull(lastName, &quot;lastName&quot;);
  1266.  }
  1267. }&lt;/code&gt;&lt;/pre&gt;
  1268. &lt;/div&gt;
  1269. &lt;/div&gt;
  1270. &lt;div class=&quot;paragraph&quot;&gt;
  1271. &lt;p&gt;Actually, this works (in a sense): JSON-B will not complain anymore about missing no-arg constructors and happily use the provided one instead.
  1272. It will also recognize the parameters as JSON properties.&lt;/p&gt;
  1273. &lt;/div&gt;
  1274. &lt;div class=&quot;paragraph&quot;&gt;
  1275. &lt;p&gt;BUT.&lt;/p&gt;
  1276. &lt;/div&gt;
  1277. &lt;div class=&quot;paragraph&quot;&gt;
  1278. &lt;p&gt;We still get an exception:&lt;/p&gt;
  1279. &lt;/div&gt;
  1280. &lt;div class=&quot;listingblock&quot;&gt;
  1281. &lt;div class=&quot;title&quot;&gt;Apache Johnzon 1.19.x error message&lt;/div&gt;
  1282. &lt;div class=&quot;content&quot;&gt;
  1283. &lt;pre class=&quot;highlightjs highlight&quot;&gt;&lt;code class=&quot;language-log hljs&quot; data-lang=&quot;log&quot;&gt;jakarta.json.bind.JsonbException:
  1284. Author cannot be constructed to deserialize json object value: {
  1285.  &quot;birth_date&quot;:&quot;1918-05-11&quot;,
  1286.  &quot;first_name&quot;:&quot;Ric...
  1287. java.lang.NullPointerException: firstName&lt;/code&gt;&lt;/pre&gt;
  1288. &lt;/div&gt;
  1289. &lt;/div&gt;
  1290. &lt;div class=&quot;listingblock&quot;&gt;
  1291. &lt;div class=&quot;title&quot;&gt;Eclipse Yasson 2 error message&lt;/div&gt;
  1292. &lt;div class=&quot;content&quot;&gt;
  1293. &lt;pre class=&quot;highlightjs highlight&quot;&gt;&lt;code class=&quot;language-log hljs&quot; data-lang=&quot;log&quot;&gt;jakarta.json.bind.JsonbException: JsonbCreator parameter firstName is missing in json document.&lt;/code&gt;&lt;/pre&gt;
  1294. &lt;/div&gt;
  1295. &lt;/div&gt;
  1296. &lt;div class=&quot;listingblock&quot;&gt;
  1297. &lt;div class=&quot;title&quot;&gt;Eclipse Yasson 3 error message&lt;/div&gt;
  1298. &lt;div class=&quot;content&quot;&gt;
  1299. &lt;pre class=&quot;highlightjs highlight&quot;&gt;&lt;code class=&quot;language-log hljs&quot; data-lang=&quot;log&quot;&gt;jakarta.json.bind.JsonbException: Exception occurred during call to JSONB creator on class: class io.github.bmarwell.jsonb.creator.value.Author.
  1300. Caused by: java.lang.reflect.InvocationTargetException
  1301. Caused by: java.lang.NullPointerException: firstName&lt;/code&gt;&lt;/pre&gt;
  1302. &lt;/div&gt;
  1303. &lt;/div&gt;
  1304. &lt;div class=&quot;paragraph&quot;&gt;
  1305. &lt;p&gt;Huh? As you can see from the Yasson 2 error message, all the implementations will look for a field &lt;code&gt;firstName&lt;/code&gt; instead of &lt;code&gt;first_name&lt;/code&gt;, although we defined a differen PropertyNamingStrategy.
  1306. Debugging Yasson3 and Apache Johnzon reveals that they are looking for the field &lt;code&gt;firstName&lt;/code&gt; as well.&lt;/p&gt;
  1307. &lt;/div&gt;
  1308. &lt;/div&gt;
  1309. &lt;/div&gt;
  1310. &lt;div class=&quot;sect1&quot;&gt;
  1311. &lt;h2 id=&quot;talking_to_romain_about_the_bug&quot;&gt;Talking to Romain about the bug&lt;/h2&gt;
  1312. &lt;div class=&quot;sectionbody&quot;&gt;
  1313. &lt;div class=&quot;paragraph&quot;&gt;
  1314. &lt;p&gt;After I made sure this &lt;strong&gt;should&lt;/strong&gt; have worked (yes, I found no different opinion in the documentation), I talked to &lt;a href=&quot;https://twitter.com/rmannibucau&quot;&gt;Romain Manni-Bucau&lt;/a&gt;, who is one of the core developers of Apache Johnzon.
  1315. He agreed that this is surprising and probably unintentional behaviour.
  1316. In fact, while talking to him on the Apache Slack, he &lt;a href=&quot;https://issues.apache.org/jira/browse/JOHNZON-390&quot;&gt;created a JIRA issue&lt;/a&gt; and &lt;a href=&quot;https://github.com/apache/johnzon/commit/b25243b23f36f257e47d8fce9b914bb5c882889c&quot;&gt;fixed the bug&lt;/a&gt; before I was even able to set up a test case.
  1317. What a magician 🧙🏻🪄 he is, indeed!&lt;/p&gt;
  1318. &lt;/div&gt;
  1319. &lt;div class=&quot;paragraph&quot;&gt;
  1320. &lt;p&gt;To make sure it works for my use case, I finished my &lt;a href=&quot;https://github.com/bmarwell/jsonb-creator-property-naming&quot;&gt;test reproducer project&lt;/a&gt;.
  1321. If you are initerested, you can test it with all four of the implementations:&lt;/p&gt;
  1322. &lt;/div&gt;
  1323. &lt;div class=&quot;listingblock&quot;&gt;
  1324. &lt;div class=&quot;content&quot;&gt;
  1325. &lt;pre class=&quot;highlightjs highlight&quot;&gt;&lt;code class=&quot;language-bash hljs&quot; data-lang=&quot;bash&quot;&gt;# Eclipse Yasson 2.0.4
  1326. ./mvnw verify -Pyasson
  1327. # Eclipse Yasson 3.0.2
  1328. ./mvnw verify -Pyasson3
  1329. # Apache Johnzon 1.2.19
  1330. ./mvnw verify -Pjohnzon
  1331. # Apache Johnzon 1.2.20-SNAPSHOT (bug fixed)
  1332. ./mvnw verify -Pjohnzon-snapshot&lt;/code&gt;&lt;/pre&gt;
  1333. &lt;/div&gt;
  1334. &lt;/div&gt;
  1335. &lt;div class=&quot;paragraph&quot;&gt;
  1336. &lt;p&gt;The results are as expected:&lt;/p&gt;
  1337. &lt;/div&gt;
  1338. &lt;div class=&quot;imageblock&quot;&gt;
  1339. &lt;div class=&quot;content&quot;&gt;
  1340. &lt;a class=&quot;image&quot; href=&quot;2022-12-09_build_partially_fixed.png&quot;&gt;&lt;img src=&quot;2022-12-09_build_partially_fixed.png&quot; alt=&quot;Build passes only with Johnzon 1.2.20&quot;&gt;&lt;/a&gt;
  1341. &lt;/div&gt;
  1342. &lt;div class=&quot;title&quot;&gt;Figure 1. Build results with Yasson 2, Yasson 3, Apache Johnzon and Apache Johnzon-SNAPSHOT.&lt;/div&gt;
  1343. &lt;/div&gt;
  1344. &lt;/div&gt;
  1345. &lt;/div&gt;
  1346. &lt;div class=&quot;sect1&quot;&gt;
  1347. &lt;h2 id=&quot;reporting_an_upstream_bug&quot;&gt;Reporting an upstream bug&lt;/h2&gt;
  1348. &lt;div class=&quot;sectionbody&quot;&gt;
  1349. &lt;div class=&quot;paragraph&quot;&gt;
  1350. &lt;p&gt;Now, we have a behaviour convergence in both implementations.
  1351. Running my app on an application Server which ships a recent version of Apache Johnzon will work,
  1352. but it would not run on any other application servers.&lt;/p&gt;
  1353. &lt;/div&gt;
  1354. &lt;div class=&quot;paragraph&quot;&gt;
  1355. &lt;p&gt;To remedy this, I also opened a bug at &lt;a href=&quot;https://github.com/eclipse-ee4j/yasson/issues/583&quot;&gt;eclipse-ee4j/yasson/issues/583&lt;/a&gt;.&lt;/p&gt;
  1356. &lt;/div&gt;
  1357. &lt;/div&gt;
  1358. &lt;/div&gt;
  1359. &lt;div class=&quot;sect1&quot;&gt;
  1360. &lt;h2 id=&quot;fixing_openliberty_using_the_bells_feature&quot;&gt;Fixing OpenLiberty using the bells-Feature&lt;/h2&gt;
  1361. &lt;div class=&quot;sectionbody&quot;&gt;
  1362. &lt;div class=&quot;paragraph&quot;&gt;
  1363. &lt;p&gt;To have the patch ready RIGHT NOW in Open Liberty, you can use the bells feature:&lt;/p&gt;
  1364. &lt;/div&gt;
  1365. &lt;div class=&quot;listingblock&quot;&gt;
  1366. &lt;div class=&quot;title&quot;&gt;Use Apache Johnzon (Jakarta) on Open Liberty&lt;/div&gt;
  1367. &lt;div class=&quot;content&quot;&gt;
  1368. &lt;pre class=&quot;highlightjs highlight&quot;&gt;&lt;code class=&quot;language-xml hljs&quot; data-lang=&quot;xml&quot;&gt;&amp;lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&amp;gt;
  1369. &amp;lt;server description=&quot;new server&quot;&amp;gt;
  1370.  &amp;lt;featureManager&amp;gt;
  1371.    &amp;lt;feature&amp;gt;jsonbContainer-2.0&amp;lt;/feature&amp;gt;
  1372.    &amp;lt;feature&amp;gt;jsonpContainer-2.0&amp;lt;/feature&amp;gt;
  1373.  &amp;lt;/featureManager&amp;gt;
  1374.  
  1375.  &amp;lt;bell libraryRef=&quot;johnzon&quot;/&amp;gt;
  1376.  
  1377.  &amp;lt;library id=&quot;johnzon&quot;&amp;gt;
  1378.    &amp;lt;fileset dir=&quot;${server.config.dir}/lib/johnzon&quot; includes=&quot;*.jar&quot;/&amp;gt;
  1379.  &amp;lt;/library&amp;gt;
  1380. &amp;lt;/server&amp;gt;&lt;/code&gt;&lt;/pre&gt;
  1381. &lt;/div&gt;
  1382. &lt;/div&gt;
  1383. &lt;div class=&quot;paragraph&quot;&gt;
  1384. &lt;p&gt;If you are using the &lt;a href=&quot;https://github.com/OpenLiberty/ci.maven&quot;&gt;liberty-maven-plugin&lt;/a&gt;, you cannot use that to download the libraries, as it does not (yet) support classifiers properly.
  1385. There is a workaround (not defining a version, so it will look into the project dependencies), but I do not like it as it does things behind your back and may end up with surprising behaviour.
  1386. It will also introduce problems when you have two similar artefacts with just different classifiers.&lt;/p&gt;
  1387. &lt;/div&gt;
  1388. &lt;div class=&quot;paragraph&quot;&gt;
  1389. &lt;p&gt;That said, this is how you download the libraries for Apache Johnzon properly:&lt;/p&gt;
  1390. &lt;/div&gt;
  1391. &lt;div class=&quot;listingblock&quot;&gt;
  1392. &lt;div class=&quot;title&quot;&gt;Deploying Apache Johnzon Jakarta Libraries into Open Liberty&lt;/div&gt;
  1393. &lt;div class=&quot;content&quot;&gt;
  1394. &lt;pre class=&quot;highlightjs highlight&quot;&gt;&lt;code class=&quot;language-xml hljs&quot; data-lang=&quot;xml&quot;&gt;&amp;lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&amp;gt;
  1395. &amp;lt;project xmlns=&quot;http://maven.apache.org/POM/4.0.0&quot;
  1396.  xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot;
  1397.  xsi:schemaLocation=&quot;http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd&quot;&amp;gt;
  1398.  &amp;lt;modelVersion&amp;gt;4.0.0&amp;lt;/modelVersion&amp;gt;
  1399.  
  1400.  &amp;lt;build&amp;gt;
  1401.    &amp;lt;plugins&amp;gt;
  1402.      &amp;lt;plugin&amp;gt;
  1403.        &amp;lt;groupId&amp;gt;io.openliberty.tools&amp;lt;/groupId&amp;gt;
  1404.        &amp;lt;artifactId&amp;gt;liberty-maven-plugin&amp;lt;/artifactId&amp;gt;
  1405.        &amp;lt;version&amp;gt;3.6.1&amp;lt;/version&amp;gt;
  1406.        &amp;lt;executions&amp;gt;
  1407.          &amp;lt;execution&amp;gt;
  1408.            &amp;lt;id&amp;gt;prepare-liberty-server&amp;lt;/id&amp;gt;
  1409.            &amp;lt;phase&amp;gt;process-test-resources&amp;lt;/phase&amp;gt;
  1410.            &amp;lt;goals&amp;gt;
  1411.              &amp;lt;goal&amp;gt;create&amp;lt;/goal&amp;gt;
  1412.              &amp;lt;goal&amp;gt;deploy&amp;lt;/goal&amp;gt;
  1413.              &amp;lt;goal&amp;gt;install-feature&amp;lt;/goal&amp;gt;
  1414.            &amp;lt;/goals&amp;gt;
  1415.          &amp;lt;/execution&amp;gt;
  1416.          &amp;lt;execution&amp;gt;
  1417.            &amp;lt;id&amp;gt;pre-it&amp;lt;/id&amp;gt;
  1418.            &amp;lt;phase&amp;gt;pre-integration-test&amp;lt;/phase&amp;gt;
  1419.            &amp;lt;goals&amp;gt;
  1420.              &amp;lt;goal&amp;gt;start&amp;lt;/goal&amp;gt;
  1421.            &amp;lt;/goals&amp;gt;
  1422.          &amp;lt;/execution&amp;gt;
  1423.          &amp;lt;execution&amp;gt;
  1424.            &amp;lt;id&amp;gt;post-it&amp;lt;/id&amp;gt;
  1425.            &amp;lt;phase&amp;gt;post-integration-test&amp;lt;/phase&amp;gt;
  1426.            &amp;lt;goals&amp;gt;
  1427.              &amp;lt;goal&amp;gt;stop&amp;lt;/goal&amp;gt;
  1428.            &amp;lt;/goals&amp;gt;
  1429.          &amp;lt;/execution&amp;gt;
  1430.        &amp;lt;/executions&amp;gt;
  1431.        &amp;lt;configuration&amp;gt;
  1432.          &amp;lt;features&amp;gt;
  1433.            &amp;lt;acceptLicense&amp;gt;true&amp;lt;/acceptLicense&amp;gt;
  1434.          &amp;lt;/features&amp;gt;
  1435.        &amp;lt;/configuration&amp;gt;
  1436.      &amp;lt;/plugin&amp;gt;
  1437.  
  1438.      &amp;lt;plugin&amp;gt;
  1439.        &amp;lt;groupId&amp;gt;org.apache.maven.plugins&amp;lt;/groupId&amp;gt;
  1440.        &amp;lt;artifactId&amp;gt;maven-dependency-plugin&amp;lt;/artifactId&amp;gt;
  1441.        &amp;lt;executions&amp;gt;
  1442.          &amp;lt;execution&amp;gt;
  1443.            &amp;lt;id&amp;gt;copy-johnzon-because-liberty-doesnt-know-about-classifiers&amp;lt;/id&amp;gt;
  1444.            &amp;lt;phase&amp;gt;process-test-resources&amp;lt;/phase&amp;gt;
  1445.            &amp;lt;goals&amp;gt;
  1446.              &amp;lt;goal&amp;gt;copy&amp;lt;/goal&amp;gt;
  1447.            &amp;lt;/goals&amp;gt;
  1448.            &amp;lt;configuration&amp;gt;
  1449.              &amp;lt;outputDirectory&amp;gt;${server.dir}/lib/johnzon&amp;lt;/outputDirectory&amp;gt;
  1450.              &amp;lt;artifactItems&amp;gt;
  1451.                &amp;lt;item&amp;gt;
  1452.                  &amp;lt;groupId&amp;gt;org.apache.johnzon&amp;lt;/groupId&amp;gt;
  1453.                  &amp;lt;artifactId&amp;gt;johnzon-core&amp;lt;/artifactId&amp;gt;
  1454.                  &amp;lt;classifier&amp;gt;jakarta&amp;lt;/classifier&amp;gt;
  1455.                  &amp;lt;version&amp;gt;${dependency.johnzon.version}&amp;lt;/version&amp;gt;
  1456.                &amp;lt;/item&amp;gt;
  1457.                &amp;lt;item&amp;gt;
  1458.                  &amp;lt;groupId&amp;gt;org.apache.johnzon&amp;lt;/groupId&amp;gt;
  1459.                  &amp;lt;artifactId&amp;gt;johnzon-jsonb&amp;lt;/artifactId&amp;gt;
  1460.                  &amp;lt;classifier&amp;gt;jakarta&amp;lt;/classifier&amp;gt;
  1461.                  &amp;lt;version&amp;gt;${dependency.johnzon.version}&amp;lt;/version&amp;gt;
  1462.                &amp;lt;/item&amp;gt;
  1463.                &amp;lt;item&amp;gt;
  1464.                  &amp;lt;groupId&amp;gt;org.apache.johnzon&amp;lt;/groupId&amp;gt;
  1465.                  &amp;lt;artifactId&amp;gt;johnzon-mapper&amp;lt;/artifactId&amp;gt;
  1466.                  &amp;lt;classifier&amp;gt;jakarta&amp;lt;/classifier&amp;gt;
  1467.                  &amp;lt;version&amp;gt;${dependency.johnzon.version}&amp;lt;/version&amp;gt;
  1468.                &amp;lt;/item&amp;gt;
  1469.              &amp;lt;/artifactItems&amp;gt;
  1470.            &amp;lt;/configuration&amp;gt;
  1471.          &amp;lt;/execution&amp;gt;
  1472.        &amp;lt;/executions&amp;gt;
  1473.      &amp;lt;/plugin&amp;gt;
  1474.    &amp;lt;/plugins&amp;gt;
  1475.  &amp;lt;/build&amp;gt;
  1476. &amp;lt;/project&amp;gt;&lt;/code&gt;&lt;/pre&gt;
  1477. &lt;/div&gt;
  1478. &lt;/div&gt;
  1479. &lt;div class=&quot;paragraph&quot;&gt;
  1480. &lt;p&gt;The configuration is a little complicated, because we need to run the &lt;code&gt;maven-dependency-plugin&lt;/code&gt; AFTER the server is created but BEFORE it is started (for obvious reasons).
  1481. Because we never know in which order the plugins were defined (thus defining the order in which they run their executions of the same phase), we need to fiddle around with different phases.
  1482. For a project which only exists for integration testing, this is easily possible.&lt;/p&gt;
  1483. &lt;/div&gt;
  1484. &lt;div class=&quot;paragraph&quot;&gt;
  1485. &lt;p&gt;But if it is also the project you are developing your web archive with, we better get the classifier introduced into Open Liberty’s maven plugin.
  1486. Guess what: &lt;a href=&quot;https://github.com/OpenLiberty/ci.maven/issues/1616&quot;&gt;Issue opened&lt;/a&gt; and &lt;a href=&quot;https://github.com/OpenLiberty/ci.maven/pull/1618&quot;&gt;PR opened&lt;/a&gt;.&lt;/p&gt;
  1487. &lt;/div&gt;
  1488. &lt;/div&gt;
  1489. &lt;/div&gt;
  1490. &lt;div class=&quot;sect1&quot;&gt;
  1491. &lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
  1492. &lt;div class=&quot;sectionbody&quot;&gt;
  1493. &lt;div class=&quot;paragraph&quot;&gt;
  1494. &lt;p&gt;As you can see from this, digging into a single issue can bring up a long tail of more problems which need to be addressed.
  1495. However, with the help of Romain and Cheryl those issues will be gone very soon, which I am very happy about.
  1496. In any case I sincerely hope this blog article will help you to see how to dig into and report a bug for Apache Software, Eclipse Libraries and even IBM’s Open Liberty server (and in this case the liberty-maven-plugin).&lt;/p&gt;
  1497. &lt;/div&gt;
  1498. &lt;div class=&quot;paragraph&quot;&gt;
  1499. &lt;p&gt;If you have any questions about this, please feel free to &lt;a href=&quot;https://twitter.com/bmarwell&quot;&gt;ask me on Twitter&lt;/a&gt; or &lt;a href=&quot;https://layer8.space/@bmarwell&quot;&gt;on Mastodon&lt;/a&gt;.&lt;/p&gt;
  1500. &lt;/div&gt;
  1501. &lt;div class=&quot;sect2&quot;&gt;
  1502. &lt;h3 id=&quot;web_links&quot;&gt;Web links&lt;/h3&gt;
  1503. &lt;div class=&quot;ulist&quot;&gt;
  1504. &lt;ul&gt;
  1505. &lt;li&gt;
  1506. &lt;p&gt;Reproducer project:&lt;br&gt;
  1507. &lt;a href=&quot;https://github.com/bmarwell/jsonb-creator-property-naming&quot; class=&quot;bare&quot;&gt;https://github.com/bmarwell/jsonb-creator-property-naming&lt;/a&gt;&lt;/p&gt;
  1508. &lt;/li&gt;
  1509. &lt;li&gt;
  1510. &lt;p&gt;Eclipse Yasson ug report:&lt;br&gt;
  1511. &lt;a href=&quot;https://github.com/eclipse-ee4j/yasson/issues/583&quot; class=&quot;bare&quot;&gt;https://github.com/eclipse-ee4j/yasson/issues/583&lt;/a&gt;&lt;/p&gt;
  1512. &lt;/li&gt;
  1513. &lt;li&gt;
  1514. &lt;p&gt;Apache Johnzon bug report:&lt;br&gt;
  1515. &lt;a href=&quot;https://issues.apache.org/jira/browse/JOHNZON-390&quot; class=&quot;bare&quot;&gt;https://issues.apache.org/jira/browse/JOHNZON-390&lt;/a&gt;&lt;/p&gt;
  1516. &lt;/li&gt;
  1517. &lt;li&gt;
  1518. &lt;p&gt;JAX-RS test showcase project which shows Open Liberty integration:&lt;br&gt;
  1519. &lt;a href=&quot;https://github.com/bmarwell/jaxrs-test-showcase&quot; class=&quot;bare&quot;&gt;https://github.com/bmarwell/jaxrs-test-showcase&lt;/a&gt;&lt;/p&gt;
  1520. &lt;/li&gt;
  1521. &lt;/ul&gt;
  1522. &lt;/div&gt;
  1523. &lt;/div&gt;
  1524. &lt;/div&gt;
  1525. &lt;/div&gt;
  1526.    </content>
  1527.  </entry>
  1528.  
  1529.  <entry>
  1530.    <!-- lang="en-GB"  -->
  1531.    <title>Set up caff with MTA correctly</title>
  1532.    <link href="https://blog.bmarwell.de/2022/10/25/setup-caff-with-mta.html"/>
  1533.    <id>https://blog.bmarwell.de/2022/10/25/setup-caff-with-mta.html</id>
  1534.    <published>2022-10-25T05:19:14Z</published>
  1535.    <updated>2022-10-25T06:32:14Z</updated>
  1536.    <author>
  1537.      <name>Benjamin Marwell</name>
  1538.    </author>
  1539.    <content type="html">
  1540.      &lt;div id=&quot;preamble&quot;&gt;
  1541. &lt;div class=&quot;sectionbody&quot;&gt;
  1542. &lt;div class=&quot;paragraph&quot;&gt;
  1543. &lt;p&gt;In my GnuPG article about &lt;a href=&quot;/series/gnupg/attending-pgp-signing-parties.html&quot;&gt;how to attend a PGP signing party&lt;/a&gt; I explained how to set up &lt;strong&gt;caff&lt;/strong&gt; using SMTP (Simple Mail Transfer Protocol).
  1544. However, using a local Mail Transfer Agent (MTA) is the more elegant solution as SMTP is not a properly supported option and discuraged, according to the caff man page or when setting &lt;code&gt;$CONFIG{&apos;mailer-send&apos;}&lt;/code&gt; to any value:&lt;/p&gt;
  1545. &lt;/div&gt;
  1546. &lt;div class=&quot;admonitionblock warning&quot;&gt;
  1547. &lt;table&gt;
  1548. &lt;tr&gt;
  1549. &lt;td class=&quot;icon&quot;&gt;
  1550. &lt;i class=&quot;fa icon-warning&quot; title=&quot;Warning&quot;&gt;&lt;/i&gt;
  1551. &lt;/td&gt;
  1552. &lt;td class=&quot;content&quot;&gt;
  1553. &lt;div class=&quot;title&quot;&gt;Warning when using &lt;code&gt;$CONFIG{&apos;mailer-send&apos;}&lt;/code&gt;&lt;/div&gt;
  1554. &lt;div class=&quot;paragraph&quot;&gt;
  1555. &lt;p&gt;Setting this option is strongly discouraged.
  1556. Fix your local MTA instead.&lt;/p&gt;
  1557. &lt;/div&gt;
  1558. &lt;/td&gt;
  1559. &lt;/tr&gt;
  1560. &lt;/table&gt;
  1561. &lt;/div&gt;
  1562. &lt;div class=&quot;paragraph&quot;&gt;
  1563. &lt;p&gt;This how-to will focus on how to send mails via &lt;a href=&quot;http://mail.google.com/&quot;&gt;&lt;strong&gt;Google Mail&lt;/strong&gt;&lt;/a&gt; (gmail).&lt;/p&gt;
  1564. &lt;/div&gt;
  1565. &lt;div id=&quot;toc&quot; class=&quot;toc&quot;&gt;
  1566. &lt;div id=&quot;toctitle&quot; class=&quot;title&quot;&gt;Table of Contents&lt;/div&gt;
  1567. &lt;ul class=&quot;sectlevel1&quot;&gt;
  1568. &lt;li&gt;&lt;a href=&quot;#installation&quot;&gt;Installation&lt;/a&gt;&lt;/li&gt;
  1569. &lt;li&gt;&lt;a href=&quot;#testing_the_mail_relay_service&quot;&gt;Testing the mail relay service&lt;/a&gt;&lt;/li&gt;
  1570. &lt;li&gt;&lt;a href=&quot;#configuring_caff&quot;&gt;Configuring CAFF&lt;/a&gt;&lt;/li&gt;
  1571. &lt;/ul&gt;
  1572. &lt;/div&gt;
  1573. &lt;/div&gt;
  1574. &lt;/div&gt;
  1575. &lt;div class=&quot;sect1&quot;&gt;
  1576. &lt;h2 id=&quot;installation&quot;&gt;Installation&lt;/h2&gt;
  1577. &lt;div class=&quot;sectionbody&quot;&gt;
  1578. &lt;div class=&quot;paragraph&quot;&gt;
  1579. &lt;p&gt;While I am not using Ubuntu anymore, installing &lt;code&gt;caff&lt;/code&gt; will also install
  1580. exim4 as a MTA.
  1581. This is not the case on Arch Linux or Manjaro, as it is an optional dependency.&lt;/p&gt;
  1582. &lt;/div&gt;
  1583. &lt;div class=&quot;paragraph&quot;&gt;
  1584. &lt;p&gt;While the German article describes how to install &lt;strong&gt;Postfix&lt;/strong&gt;, for this english version I decided to use &lt;strong&gt;postfix&lt;/strong&gt; on &lt;strong&gt;Manjaro&lt;/strong&gt;.
  1585. While &lt;strong&gt;dma&lt;/strong&gt; would have been a great choice, too, it currently does not support TLSv1.2 and is thus defunct.&lt;/p&gt;
  1586. &lt;/div&gt;
  1587. &lt;div class=&quot;listingblock&quot;&gt;
  1588. &lt;div class=&quot;title&quot;&gt;Installing the dependencies&lt;/div&gt;
  1589. &lt;div class=&quot;content&quot;&gt;
  1590. &lt;pre class=&quot;highlightjs highlight&quot;&gt;&lt;code class=&quot;language-bash hljs&quot; data-lang=&quot;bash&quot;&gt;# Using paru on Arch/Manjaro:
  1591. paru -Syu signing-party postfix
  1592.  
  1593. # Using apt-get on Ubuntu and Debian:
  1594. apt-get install signing-party postfix libsasl2-modules exim4_ mailx&lt;/code&gt;&lt;/pre&gt;
  1595. &lt;/div&gt;
  1596. &lt;/div&gt;
  1597. &lt;div class=&quot;paragraph&quot;&gt;
  1598. &lt;p&gt;The configuration is done in just two files:&lt;/p&gt;
  1599. &lt;/div&gt;
  1600. &lt;div class=&quot;listingblock&quot;&gt;
  1601. &lt;div class=&quot;title&quot;&gt;/etc/postfix/aliases.conf&lt;/div&gt;
  1602. &lt;div class=&quot;content&quot;&gt;
  1603. &lt;pre class=&quot;highlightjs highlight&quot;&gt;&lt;code class=&quot;language-conf hljs&quot; data-lang=&quot;conf&quot;&gt;root: user&lt;/code&gt;&lt;/pre&gt;
  1604. &lt;/div&gt;
  1605. &lt;/div&gt;
  1606. &lt;div class=&quot;paragraph&quot;&gt;
  1607. &lt;p&gt;Then reload the changes:&lt;/p&gt;
  1608. &lt;/div&gt;
  1609. &lt;div class=&quot;listingblock&quot;&gt;
  1610. &lt;div class=&quot;content&quot;&gt;
  1611. &lt;pre class=&quot;highlightjs highlight&quot;&gt;&lt;code class=&quot;language-bash hljs&quot; data-lang=&quot;bash&quot;&gt;sudo postalias /etc/postfix/aliases&lt;/code&gt;&lt;/pre&gt;
  1612. &lt;/div&gt;
  1613. &lt;/div&gt;
  1614. &lt;div class=&quot;listingblock&quot;&gt;
  1615. &lt;div class=&quot;title&quot;&gt;/etc/postfix/sasl_password&lt;/div&gt;
  1616. &lt;div class=&quot;content&quot;&gt;
  1617. &lt;pre class=&quot;highlightjs highlight&quot;&gt;&lt;code class=&quot;language-conf hljs&quot; data-lang=&quot;conf&quot;&gt;smtp.gmail.com:587 myMail@gmail.com:clear-text-password&lt;/code&gt;&lt;/pre&gt;
  1618. &lt;/div&gt;
  1619. &lt;/div&gt;
  1620. &lt;div class=&quot;listingblock&quot;&gt;
  1621. &lt;div class=&quot;content&quot;&gt;
  1622. &lt;pre class=&quot;highlightjs highlight&quot;&gt;&lt;code class=&quot;language-bash hljs&quot; data-lang=&quot;bash&quot;&gt;sudo chmod 0600 /etc/postfix/sasl_password&lt;/code&gt;&lt;/pre&gt;
  1623. &lt;/div&gt;
  1624. &lt;/div&gt;
  1625. &lt;div class=&quot;listingblock&quot;&gt;
  1626. &lt;div class=&quot;title&quot;&gt;/etc/postfix/sender_canonical: Mapping your local user&lt;/div&gt;
  1627. &lt;div class=&quot;content&quot;&gt;
  1628. &lt;pre class=&quot;highlightjs highlight&quot;&gt;&lt;code class=&quot;language-conf hljs&quot; data-lang=&quot;conf&quot;&gt;user gmail_user@gmail.com&lt;/code&gt;&lt;/pre&gt;
  1629. &lt;/div&gt;
  1630. &lt;/div&gt;
  1631. &lt;div class=&quot;listingblock&quot;&gt;
  1632. &lt;div class=&quot;title&quot;&gt;Reading the settings&lt;/div&gt;
  1633. &lt;div class=&quot;content&quot;&gt;
  1634. &lt;pre class=&quot;highlightjs highlight&quot;&gt;&lt;code class=&quot;language-bash hljs&quot; data-lang=&quot;bash&quot;&gt;sudo postmap /etc/postfix/sender_canonical&lt;/code&gt;&lt;/pre&gt;
  1635. &lt;/div&gt;
  1636. &lt;/div&gt;
  1637. &lt;div class=&quot;listingblock&quot;&gt;
  1638. &lt;div class=&quot;title&quot;&gt;/etc/postfix/main.cf: Letting postfix know about the relay conf&lt;/div&gt;
  1639. &lt;div class=&quot;content&quot;&gt;
  1640. &lt;pre class=&quot;highlightjs highlight&quot;&gt;&lt;code class=&quot;language-conf hljs&quot; data-lang=&quot;conf&quot;&gt;smtp_sasl_auth_enable = yes
  1641. smtp_tls_security_level = encrypt
  1642. relayhost = [smtp.gmail.com]:587
  1643. smtp_sasl_security_options = noanonymous
  1644. smtp_sasl_password_maps = hash:/etc/postfix/sasl_password
  1645. sender_canonical_maps = hash:/etc/postfix/sender_canonical&lt;/code&gt;&lt;/pre&gt;
  1646. &lt;/div&gt;
  1647. &lt;/div&gt;
  1648. &lt;div class=&quot;listingblock&quot;&gt;
  1649. &lt;div class=&quot;title&quot;&gt;Enable the postfix daemon&lt;/div&gt;
  1650. &lt;div class=&quot;content&quot;&gt;
  1651. &lt;pre class=&quot;highlightjs highlight&quot;&gt;&lt;code class=&quot;language-bash hljs&quot; data-lang=&quot;bash&quot;&gt;sudo systemctl enable postfix --now&lt;/code&gt;&lt;/pre&gt;
  1652. &lt;/div&gt;
  1653. &lt;/div&gt;
  1654. &lt;/div&gt;
  1655. &lt;/div&gt;
  1656. &lt;div class=&quot;sect1&quot;&gt;
  1657. &lt;h2 id=&quot;testing_the_mail_relay_service&quot;&gt;Testing the mail relay service&lt;/h2&gt;
  1658. &lt;div class=&quot;sectionbody&quot;&gt;
  1659. &lt;div class=&quot;paragraph&quot;&gt;
  1660. &lt;p&gt;Now everything should work.&lt;/p&gt;
  1661. &lt;/div&gt;
  1662. &lt;div class=&quot;listingblock&quot;&gt;
  1663. &lt;div class=&quot;title&quot;&gt;Testing postfix via gmail&lt;/div&gt;
  1664. &lt;div class=&quot;content&quot;&gt;
  1665. &lt;pre class=&quot;highlightjs highlight&quot;&gt;&lt;code class=&quot;language-bash hljs&quot; data-lang=&quot;bash&quot;&gt;mail -s &quot;subject&quot; my_user@gmail.com
  1666.  Write some text here.
  1667.  When you are done, press CTRL+d:
  1668.  ^D
  1669.  
  1670. # check the postfix logs for errors:
  1671. journalctl -ru postfix | head -n 10&lt;/code&gt;&lt;/pre&gt;
  1672. &lt;/div&gt;
  1673. &lt;/div&gt;
  1674. &lt;div class=&quot;paragraph&quot;&gt;
  1675. &lt;p&gt;In case your mail has arrived, you are done!&lt;/p&gt;
  1676. &lt;/div&gt;
  1677. &lt;/div&gt;
  1678. &lt;/div&gt;
  1679. &lt;div class=&quot;sect1&quot;&gt;
  1680. &lt;h2 id=&quot;configuring_caff&quot;&gt;Configuring CAFF&lt;/h2&gt;
  1681. &lt;div class=&quot;sectionbody&quot;&gt;
  1682. &lt;div class=&quot;paragraph&quot;&gt;
  1683. &lt;p&gt;If not already done, make sure the line &lt;code&gt;$CONFIG{&apos;mailer-send&apos;}&lt;/code&gt; is commented.
  1684. Now use caff as you would normally.&lt;/p&gt;
  1685. &lt;/div&gt;
  1686. &lt;div class=&quot;imageblock&quot;&gt;
  1687. &lt;div class=&quot;content&quot;&gt;
  1688. &lt;a class=&quot;image&quot; href=&quot;./2022-10-25_caff-testrun.png&quot;&gt;&lt;img src=&quot;./2022-10-25_caff-testrun.png&quot; alt=&quot;Screenshot of caff example output&quot;&gt;&lt;/a&gt;
  1689. &lt;/div&gt;
  1690. &lt;div class=&quot;title&quot;&gt;Figure 1. Screenshot of caff example output&lt;/div&gt;
  1691. &lt;/div&gt;
  1692. &lt;/div&gt;
  1693. &lt;/div&gt;
  1694.    </content>
  1695.  </entry>
  1696.  
  1697.  <entry>
  1698.    <!-- lang="en-GB"  -->
  1699.    <title>Testing JAX-RS applications with system tests</title>
  1700.    <link href="https://blog.bmarwell.de/2022/10/24/testing-jaxrs-with-systemtests.html"/>
  1701.    <id>https://blog.bmarwell.de/2022/10/24/testing-jaxrs-with-systemtests.html</id>
  1702.    <published>2022-10-24T14:19:14Z</published>
  1703.    <updated>2022-10-24T14:32:14Z</updated>
  1704.    <author>
  1705.      <name>Benjamin Marwell</name>
  1706.    </author>
  1707.    <content type="html">
  1708.      &lt;div id=&quot;preamble&quot;&gt;
  1709. &lt;div class=&quot;sectionbody&quot;&gt;
  1710. &lt;div class=&quot;paragraph&quot;&gt;
  1711. &lt;p&gt;In case you ever developed a Jakarta Web application, you might wonder &lt;strong&gt;how to test JAX-RS applications&lt;/strong&gt;.
  1712. Luckily, while not perfectly documented, testing a JAX-RS application can be done in a few ways.
  1713. This article covers &lt;strong&gt;system tests&lt;/strong&gt;, which are somewhere between unit tests and integration tests.&lt;/p&gt;
  1714. &lt;/div&gt;
  1715. &lt;div id=&quot;toc&quot; class=&quot;toc&quot;&gt;
  1716. &lt;div id=&quot;toctitle&quot; class=&quot;title&quot;&gt;Table of Contents&lt;/div&gt;
  1717. &lt;ul class=&quot;sectlevel1&quot;&gt;
  1718. &lt;li&gt;&lt;a href=&quot;#definition_of_system_tests&quot;&gt;Definition of system tests&lt;/a&gt;
  1719. &lt;ul class=&quot;sectlevel2&quot;&gt;
  1720. &lt;li&gt;&lt;a href=&quot;#when_to_use_system_tests&quot;&gt;When to use system tests&lt;/a&gt;&lt;/li&gt;
  1721. &lt;/ul&gt;
  1722. &lt;/li&gt;
  1723. &lt;li&gt;&lt;a href=&quot;#setting_up_a_maven_project_with_system_tests&quot;&gt;Setting up a maven project with system tests&lt;/a&gt;
  1724. &lt;ul class=&quot;sectlevel2&quot;&gt;
  1725. &lt;li&gt;&lt;a href=&quot;#choosing_your_implementations&quot;&gt;Choosing your implementations&lt;/a&gt;&lt;/li&gt;
  1726. &lt;li&gt;&lt;a href=&quot;#creating_the_tests&quot;&gt;Creating the tests&lt;/a&gt;&lt;/li&gt;
  1727. &lt;li&gt;&lt;a href=&quot;#choosing_the_json_b_implementation&quot;&gt;Choosing the JSON-B implementation&lt;/a&gt;&lt;/li&gt;
  1728. &lt;li&gt;&lt;a href=&quot;#choosing_the_jax_rs_implementation&quot;&gt;Choosing the JAX-RS implementation&lt;/a&gt;&lt;/li&gt;
  1729. &lt;li&gt;&lt;a href=&quot;#adding_a_messagebodywriter&quot;&gt;Adding a MessageBodyWriter&lt;/a&gt;&lt;/li&gt;
  1730. &lt;/ul&gt;
  1731. &lt;/li&gt;
  1732. &lt;li&gt;&lt;a href=&quot;#implementing_tests&quot;&gt;Implementing tests&lt;/a&gt;
  1733. &lt;ul class=&quot;sectlevel2&quot;&gt;
  1734. &lt;li&gt;&lt;a href=&quot;#eclipse_jersey_just_start_writing_tests&quot;&gt;Eclipse Jersey: Just start writing tests&lt;/a&gt;&lt;/li&gt;
  1735. &lt;li&gt;&lt;a href=&quot;#apache_cxf_writing_a_junit_jupiter_extension&quot;&gt;Apache CXF: Writing a Junit-Jupiter extension&lt;/a&gt;&lt;/li&gt;
  1736. &lt;li&gt;&lt;a href=&quot;#jboss_resteasy&quot;&gt;JBoss RestEasy&lt;/a&gt;&lt;/li&gt;
  1737. &lt;/ul&gt;
  1738. &lt;/li&gt;
  1739. &lt;li&gt;&lt;a href=&quot;#outlook&quot;&gt;Outlook&lt;/a&gt;&lt;/li&gt;
  1740. &lt;li&gt;&lt;a href=&quot;#references&quot;&gt;References&lt;/a&gt;&lt;/li&gt;
  1741. &lt;/ul&gt;
  1742. &lt;/div&gt;
  1743. &lt;/div&gt;
  1744. &lt;/div&gt;
  1745. &lt;div class=&quot;sect1&quot;&gt;
  1746. &lt;h2 id=&quot;definition_of_system_tests&quot;&gt;Definition of system tests&lt;/h2&gt;
  1747. &lt;div class=&quot;sectionbody&quot;&gt;
  1748. &lt;div class=&quot;paragraph&quot;&gt;
  1749. &lt;p&gt;To define the category of a &lt;strong&gt;system test&lt;/strong&gt;, let‘s first look at what we already know about exist tests mechanisms.&lt;/p&gt;
  1750. &lt;/div&gt;
  1751. &lt;div class=&quot;dlist&quot;&gt;
  1752. &lt;dl&gt;
  1753. &lt;dt class=&quot;hdlist1&quot;&gt;Unit tests&lt;/dt&gt;
  1754. &lt;dd&gt;
  1755. &lt;p&gt;For unit tests, we instantiate the class under test ourselves.
  1756. All required dependencies (e.g. services, usually injected via CDI) are created manually using mocks and set via a &lt;code&gt;set()&lt;/code&gt; method.
  1757. The response can be twofold.
  1758. In case you return a POJO, you will just receive that exactly same POJO from your method call.
  1759. The same is true for a &lt;code&gt;Response&lt;/code&gt; object.
  1760. No conversion of the entity within will be done.
  1761. You will still need a &lt;code&gt;Response&lt;/code&gt; implementation in your class path.&lt;/p&gt;
  1762. &lt;/dd&gt;
  1763. &lt;dt class=&quot;hdlist1&quot;&gt;Integration tests&lt;/dt&gt;
  1764. &lt;dd&gt;
  1765. &lt;p&gt;Class integration tests start a container and deploy the &lt;strong&gt;real&lt;/strong&gt; application before the test suites are being executed.
  1766. Some prefer arquillian to set up your container,
  1767. while others will just start the container using various maven plugins like the &lt;code&gt;maven-failsafe-plugin&lt;/code&gt; and maybe plugins provided by your favourite application server.
  1768. For me, this would be the &lt;a href=&quot;https://github.com/OpenLiberty/ci.maven&quot;&gt;&lt;code&gt;io.openliberty.tools:liberty-maven-plugin&lt;/code&gt;&lt;/a&gt; which handles downloading the server binaries, the needed features, deploying the application and starting and stopping the application server.
  1769. Also, it is somewhat more difficult to set up coverage.&lt;/p&gt;
  1770. &lt;/dd&gt;
  1771. &lt;dt class=&quot;hdlist1&quot;&gt;System tests&lt;/dt&gt;
  1772. &lt;dd&gt;
  1773. &lt;p&gt;Now, there are system tests, too.
  1774. As stated before, they are somewhere in between unit and integration tests.
  1775. They do start a JAX-RS implementation instance, but they do not use other parts of a full blown JakartaEE container.
  1776. There is no CDI (which is similar to unit testing), but there is a transport (either via http, or in-memory) and all instances are initialized via the meachnisms of JakartaEE.
  1777. Another benefit of these tests are that they can run in a unit-test context where coverage is easy to set up.&lt;/p&gt;
  1778. &lt;/dd&gt;
  1779. &lt;/dl&gt;
  1780. &lt;/div&gt;
  1781. &lt;div class=&quot;sect2&quot;&gt;
  1782. &lt;h3 id=&quot;when_to_use_system_tests&quot;&gt;When to use system tests&lt;/h3&gt;
  1783. &lt;div class=&quot;paragraph&quot;&gt;
  1784. &lt;p&gt;Now that you have a bird‘s-eye view of system tests, let us look where they excel.&lt;/p&gt;
  1785. &lt;/div&gt;
  1786. &lt;div class=&quot;olist arabic&quot;&gt;
  1787. &lt;ol class=&quot;arabic&quot;&gt;
  1788. &lt;li&gt;
  1789. &lt;p&gt;System tests are fast.&lt;br&gt;
  1790. They are (almost) as fast as unit tests if done right.
  1791. Or in pther words: they are cheap to execute.
  1792. You can create lots of them without adding too much time to your build, compared to integration tests.&lt;/p&gt;
  1793. &lt;/li&gt;
  1794. &lt;li&gt;
  1795. &lt;p&gt;System tests have meaning.&lt;br&gt;
  1796. While unit tests do not use implementations of &lt;code&gt;MessageBodyReader&lt;/code&gt; or &lt;code&gt;MessageBodyWriter&lt;/code&gt;, system tests do.
  1797. They also use parameter converters, because you send strings via a transport.&lt;/p&gt;
  1798. &lt;/li&gt;
  1799. &lt;/ol&gt;
  1800. &lt;/div&gt;
  1801. &lt;div class=&quot;paragraph&quot;&gt;
  1802. &lt;p&gt;That said, you should use system tests to test all of your endpoints.
  1803. Leave unit tests only to a few logic methods in your JAX-RS endpoint&amp;#8201;&amp;#8212;&amp;#8201;you should not have too many of those methods in your endpoints anyway.
  1804. To test wheter your injection works, the application runs on your app server, use a few integration tests.
  1805. For everything else, system tests are great!&lt;/p&gt;
  1806. &lt;/div&gt;
  1807. &lt;/div&gt;
  1808. &lt;/div&gt;
  1809. &lt;/div&gt;
  1810. &lt;div class=&quot;sect1&quot;&gt;
  1811. &lt;h2 id=&quot;setting_up_a_maven_project_with_system_tests&quot;&gt;Setting up a maven project with system tests&lt;/h2&gt;
  1812. &lt;div class=&quot;sectionbody&quot;&gt;
  1813. &lt;div class=&quot;paragraph&quot;&gt;
  1814. &lt;p&gt;First thing you need is a maven project (obviously) with a few application modules.
  1815. One module should be your &lt;code&gt;war&lt;/code&gt; module you are testing, contianing an &lt;code&gt;Application&lt;/code&gt; class and the endpoints.&lt;/p&gt;
  1816. &lt;/div&gt;
  1817. &lt;div class=&quot;paragraph&quot;&gt;
  1818. &lt;p&gt;For my example, I created only a few additional modules:&lt;/p&gt;
  1819. &lt;/div&gt;
  1820. &lt;div class=&quot;ulist&quot;&gt;
  1821. &lt;ul&gt;
  1822. &lt;li&gt;
  1823. &lt;p&gt;&lt;code&gt;services/api&lt;/code&gt;&amp;#8201;&amp;#8212;&amp;#8201;where the interfaces for service classes are defined,&lt;/p&gt;
  1824. &lt;/li&gt;
  1825. &lt;li&gt;
  1826. &lt;p&gt;&lt;code&gt;services/impl&lt;/code&gt;&amp;#8201;&amp;#8212;&amp;#8201;where the service implementation delegates to some backend (JPA, mongoDB, whatever).
  1827. We do not use such modules in system tests, usually.
  1828. But you can, if the implementation is lightweight enough!&lt;/p&gt;
  1829. &lt;/li&gt;
  1830. &lt;li&gt;
  1831. &lt;p&gt;&lt;code&gt;commons/value&lt;/code&gt;&amp;#8201;&amp;#8212;&amp;#8201;common value classes, e.g. ID classes or parameters which can be used throughout the entire application.&lt;/p&gt;
  1832. &lt;/li&gt;
  1833. &lt;li&gt;
  1834. &lt;p&gt;&lt;code&gt;web/rest-v1&lt;/code&gt;&amp;#8201;&amp;#8212;&amp;#8201;(war) the actual JAX-RS module.&lt;/p&gt;
  1835. &lt;/li&gt;
  1836. &lt;li&gt;
  1837. &lt;p&gt;&lt;code&gt;web/api&lt;/code&gt;&amp;#8201;&amp;#8212;&amp;#8201;extracted interfaces of the JAX-RS application.&lt;/p&gt;
  1838. &lt;/li&gt;
  1839. &lt;/ul&gt;
  1840. &lt;/div&gt;
  1841. &lt;div class=&quot;paragraph&quot;&gt;
  1842. &lt;p&gt;You may wonder why the interfaces for the modules are needed.
  1843. Well, one of the JAX-RS implementations can use the interfaces to create a client.
  1844. This will not part of THIS tutorial, but may be covered in consecutive tutorials.
  1845. A big drawback: You need to repeat all of the annotations everywhere.&lt;/p&gt;
  1846. &lt;/div&gt;
  1847. &lt;div class=&quot;exampleblock&quot;&gt;
  1848. &lt;div class=&quot;title&quot;&gt;Example 1. Sample project&lt;/div&gt;
  1849. &lt;div class=&quot;content&quot;&gt;
  1850. &lt;div class=&quot;paragraph&quot;&gt;
  1851. &lt;p&gt;For the rest of this tutorial, I will use my sample project as a reference:
  1852. &lt;a href=&quot;https://github.com/bmarwell/jaxrs-testing-showcase&quot; class=&quot;bare&quot;&gt;https://github.com/bmarwell/jaxrs-testing-showcase&lt;/a&gt;&lt;/p&gt;
  1853. &lt;/div&gt;
  1854. &lt;/div&gt;
  1855. &lt;/div&gt;
  1856. &lt;div class=&quot;sect2&quot;&gt;
  1857. &lt;h3 id=&quot;choosing_your_implementations&quot;&gt;Choosing your implementations&lt;/h3&gt;
  1858. &lt;div class=&quot;paragraph&quot;&gt;
  1859. &lt;p&gt;While my showcase project will test multiple combinations of JAX-RS and JSONB-implementations, this is usually not needed.
  1860. They are all mature and compatible with each other.
  1861. However, my project is thought of a sample for most combinations, so chose your poison! :)&lt;/p&gt;
  1862. &lt;/div&gt;
  1863. &lt;div class=&quot;sect3&quot;&gt;
  1864. &lt;h4 id=&quot;jax_rs_implementations&quot;&gt;JAX-RS implementations&lt;/h4&gt;
  1865. &lt;div class=&quot;paragraph&quot;&gt;
  1866. &lt;p&gt;There are three main implementations:&lt;/p&gt;
  1867. &lt;/div&gt;
  1868. &lt;div class=&quot;dlist&quot;&gt;
  1869. &lt;dl&gt;
  1870. &lt;dt class=&quot;hdlist1&quot;&gt;Eclipse Jersey&lt;/dt&gt;
  1871. &lt;dd&gt;
  1872. &lt;p&gt;Provided by the Eclipse Foundation, this is the reference implementation.
  1873. It is used widely in many application servers.&lt;/p&gt;
  1874. &lt;/dd&gt;
  1875. &lt;dt class=&quot;hdlist1&quot;&gt;Apache CXF&lt;/dt&gt;
  1876. &lt;dd&gt;
  1877. &lt;p&gt;Best known for their JAX-WS support (xml+soap!), they also added a mature JAX-RS component.
  1878. It was the main implementation of &lt;a href=&quot;https://openliberty.io&quot;&gt;Open Liberty&lt;/a&gt;.
  1879. Most other Apache application servers use Apache CXF, e.g. Apache TomEE.
  1880. However, as no JakartaEE support was released recently, some application servers switched to other implementations.&lt;/p&gt;
  1881. &lt;/dd&gt;
  1882. &lt;dt class=&quot;hdlist1&quot;&gt;JBoss RestEasy&lt;/dt&gt;
  1883. &lt;dd&gt;
  1884. &lt;p&gt;JBoss‘ take on JAX-RS.
  1885. It features helpful additions like form/multipart capable endpoints.&lt;/p&gt;
  1886. &lt;/dd&gt;
  1887. &lt;/dl&gt;
  1888. &lt;/div&gt;
  1889. &lt;/div&gt;
  1890. &lt;div class=&quot;sect3&quot;&gt;
  1891. &lt;h4 id=&quot;json_b_implementations&quot;&gt;JSON-B implementations&lt;/h4&gt;
  1892. &lt;div class=&quot;paragraph&quot;&gt;
  1893. &lt;p&gt;JSON-B (JSON-Binding) is the default component when (de)serializing JSON for JAX-RS.
  1894. Implementations include:&lt;/p&gt;
  1895. &lt;/div&gt;
  1896. &lt;div class=&quot;dlist&quot;&gt;
  1897. &lt;dl&gt;
  1898. &lt;dt class=&quot;hdlist1&quot;&gt;Eclipse Yasson&lt;/dt&gt;
  1899. &lt;dd&gt;
  1900. &lt;p&gt;Again, Eclipse provides the default implementation.
  1901. It is used by many application servers.&lt;/p&gt;
  1902. &lt;/dd&gt;
  1903. &lt;dt class=&quot;hdlist1&quot;&gt;Apache Johnzon&lt;/dt&gt;
  1904. &lt;dd&gt;
  1905. &lt;p&gt;Also a very mature implementation, it is featured by Apache TomEE.&lt;/p&gt;
  1906. &lt;/dd&gt;
  1907. &lt;/dl&gt;
  1908. &lt;/div&gt;
  1909. &lt;/div&gt;
  1910. &lt;/div&gt;
  1911. &lt;div class=&quot;sect2&quot;&gt;
  1912. &lt;h3 id=&quot;creating_the_tests&quot;&gt;Creating the tests&lt;/h3&gt;
  1913. &lt;div class=&quot;paragraph&quot;&gt;
  1914. &lt;p&gt;You can now chose whether to include tests in your JAX-RS module or to make a seperate module.
  1915. Usually, there is not gain in creating a separate module except you can use multiple modules for multiple implementations.
  1916. Since this is rarely the case, you can just stick to having no additional module.&lt;/p&gt;
  1917. &lt;/div&gt;
  1918. &lt;div class=&quot;paragraph&quot;&gt;
  1919. &lt;p&gt;Another benefit might be the fact that your other tests should not inherit the classpath of the JAX-RS implementation.
  1920. In this case, multiple modules can be useful.&lt;/p&gt;
  1921. &lt;/div&gt;
  1922. &lt;div class=&quot;paragraph&quot;&gt;
  1923. &lt;p&gt;Another benefit of more modules:
  1924. Their execution are easier to control via profiles.&lt;/p&gt;
  1925. &lt;/div&gt;
  1926. &lt;div class=&quot;paragraph&quot;&gt;
  1927. &lt;p&gt;Another thing to chose is whether to name them &lt;code&gt;*Test&lt;/code&gt; or &lt;code&gt;*IT&lt;/code&gt;.
  1928. This will have impact on coverage (depending on your coverage configuration) and by which plugin the tests are executed.
  1929. I usually just go for &lt;code&gt;*Test&lt;/code&gt; as there is little drawback.
  1930. If you need more fine-grained control, you can use JUnit &lt;code&gt;@Tag()&lt;/code&gt; (5/Jupiter) or &lt;code&gt;@Category()&lt;/code&gt; (Junit 4).`&lt;/p&gt;
  1931. &lt;/div&gt;
  1932. &lt;/div&gt;
  1933. &lt;div class=&quot;sect2&quot;&gt;
  1934. &lt;h3 id=&quot;choosing_the_json_b_implementation&quot;&gt;Choosing the JSON-B implementation&lt;/h3&gt;
  1935. &lt;div class=&quot;paragraph&quot;&gt;
  1936. &lt;p&gt;For the JSON configuration, there is not much to it.
  1937. Just drop the desired implementaiton dependency into your class path, e.&amp;#160;g.  one of the following dependencies:&lt;/p&gt;
  1938. &lt;/div&gt;
  1939. &lt;div class=&quot;listingblock&quot;&gt;
  1940. &lt;div class=&quot;title&quot;&gt;Dependencies for JSON-B implementations&lt;/div&gt;
  1941. &lt;div class=&quot;content&quot;&gt;
  1942. &lt;pre class=&quot;highlightjs highlight&quot;&gt;&lt;code class=&quot;language-xml hljs&quot; data-lang=&quot;xml&quot;&gt;&amp;lt;project&amp;gt;
  1943.  &amp;lt;properties&amp;gt;
  1944.    &amp;lt;dependency.johnzon.version&amp;gt;1.2.19&amp;lt;/dependency.johnzon.version&amp;gt;
  1945.    &amp;lt;dependency.yasson.version&amp;gt;3.0.2&amp;lt;/dependency.yasson.version&amp;gt;
  1946.  &amp;lt;/properties&amp;gt;
  1947.  
  1948.  &amp;lt;dependencies&amp;gt;
  1949.    &amp;lt;dependency&amp;gt;
  1950.      &amp;lt;groupId&amp;gt;jakarta.json.bind&amp;lt;/groupId&amp;gt;
  1951.      &amp;lt;artifactId&amp;gt;jakarta.json.bind-api&amp;lt;/artifactId&amp;gt;
  1952.      &amp;lt;scope&amp;gt;test&amp;lt;/scope&amp;gt;
  1953.    &amp;lt;/dependency&amp;gt;
  1954.    &amp;lt;dependency&amp;gt;
  1955.      &amp;lt;groupId&amp;gt;jakarta.json&amp;lt;/groupId&amp;gt;
  1956.      &amp;lt;artifactId&amp;gt;jakarta.json-api&amp;lt;/artifactId&amp;gt;
  1957.      &amp;lt;scope&amp;gt;test&amp;lt;/scope&amp;gt;
  1958.    &amp;lt;/dependency&amp;gt;
  1959.  
  1960.  
  1961.    &amp;lt;!-- Apache Johnzon --&amp;gt;
  1962.    &amp;lt;dependency&amp;gt;
  1963.      &amp;lt;groupId&amp;gt;org.apache.johnzon&amp;lt;/groupId&amp;gt;
  1964.      &amp;lt;artifactId&amp;gt;johnzon-core&amp;lt;/artifactId&amp;gt;
  1965.      &amp;lt;classifier&amp;gt;jakarta&amp;lt;/classifier&amp;gt;
  1966.      &amp;lt;version&amp;gt;${dependency.johnzon.version}&amp;lt;/version&amp;gt;
  1967.      &amp;lt;scope&amp;gt;test&amp;lt;/scope&amp;gt;
  1968.      &amp;lt;exclusions&amp;gt;
  1969.        &amp;lt;exclusion&amp;gt;
  1970.          &amp;lt;groupId&amp;gt;*&amp;lt;/groupId&amp;gt;
  1971.          &amp;lt;artifactId&amp;gt;*&amp;lt;/artifactId&amp;gt;
  1972.        &amp;lt;/exclusion&amp;gt;
  1973.      &amp;lt;/exclusions&amp;gt;
  1974.    &amp;lt;/dependency&amp;gt;
  1975.    &amp;lt;dependency&amp;gt;
  1976.      &amp;lt;groupId&amp;gt;org.apache.johnzon&amp;lt;/groupId&amp;gt;
  1977.      &amp;lt;artifactId&amp;gt;johnzon-jsonb&amp;lt;/artifactId&amp;gt;
  1978.      &amp;lt;classifier&amp;gt;jakarta&amp;lt;/classifier&amp;gt;
  1979.      &amp;lt;version&amp;gt;${dependency.johnzon.version}&amp;lt;/version&amp;gt;
  1980.      &amp;lt;scope&amp;gt;test&amp;lt;/scope&amp;gt;
  1981.      &amp;lt;exclusions&amp;gt;
  1982.        &amp;lt;exclusion&amp;gt;
  1983.          &amp;lt;groupId&amp;gt;*&amp;lt;/groupId&amp;gt;
  1984.          &amp;lt;artifactId&amp;gt;*&amp;lt;/artifactId&amp;gt;
  1985.        &amp;lt;/exclusion&amp;gt;
  1986.      &amp;lt;/exclusions&amp;gt;
  1987.    &amp;lt;/dependency&amp;gt;
  1988.    &amp;lt;dependency&amp;gt;
  1989.      &amp;lt;groupId&amp;gt;org.apache.johnzon&amp;lt;/groupId&amp;gt;
  1990.      &amp;lt;artifactId&amp;gt;johnzon-mapper&amp;lt;/artifactId&amp;gt;
  1991.      &amp;lt;classifier&amp;gt;jakarta&amp;lt;/classifier&amp;gt;
  1992.      &amp;lt;version&amp;gt;${dependency.johnzon.version}&amp;lt;/version&amp;gt;
  1993.      &amp;lt;scope&amp;gt;test&amp;lt;/scope&amp;gt;
  1994.      &amp;lt;exclusions&amp;gt;
  1995.        &amp;lt;exclusion&amp;gt;
  1996.          &amp;lt;groupId&amp;gt;*&amp;lt;/groupId&amp;gt;
  1997.          &amp;lt;artifactId&amp;gt;*&amp;lt;/artifactId&amp;gt;
  1998.        &amp;lt;/exclusion&amp;gt;
  1999.      &amp;lt;/exclusions&amp;gt;
  2000.    &amp;lt;/dependency&amp;gt;
  2001.  
  2002.    &amp;lt;!-- Eclipse Yasson --&amp;gt;
  2003.    &amp;lt;dependency&amp;gt;
  2004.      &amp;lt;groupId&amp;gt;org.eclipse&amp;lt;/groupId&amp;gt;
  2005.      &amp;lt;artifactId&amp;gt;yasson&amp;lt;/artifactId&amp;gt;
  2006.      &amp;lt;version&amp;gt;${dependency.yasson.version}&amp;lt;/version&amp;gt;
  2007.      &amp;lt;scope&amp;gt;test&amp;lt;/scope&amp;gt;
  2008.    &amp;lt;/dependency&amp;gt;
  2009.  &amp;lt;/dependencies&amp;gt;
  2010. &amp;lt;/project&amp;gt;&lt;/code&gt;&lt;/pre&gt;
  2011. &lt;/div&gt;
  2012. &lt;/div&gt;
  2013. &lt;div class=&quot;paragraph&quot;&gt;
  2014. &lt;p&gt;A few additional comments here:&lt;/p&gt;
  2015. &lt;/div&gt;
  2016. &lt;div class=&quot;ulist&quot;&gt;
  2017. &lt;ul&gt;
  2018. &lt;li&gt;
  2019. &lt;p&gt;The johnzon dependency list is very long.
  2020. This is due to the fact that they use classifiers for the jakarta namespace support, but the transitive dependencies do not.
  2021. Hence, we need to exclude those and add them in later.&lt;/p&gt;
  2022. &lt;/li&gt;
  2023. &lt;li&gt;
  2024. &lt;p&gt;The scope is set to set for the JSON-Bind API.
  2025. The correct scope would be &lt;code&gt;provided&lt;/code&gt; for the web project and &lt;code&gt;test&lt;/code&gt; for the tests.&lt;/p&gt;
  2026. &lt;/li&gt;
  2027. &lt;/ul&gt;
  2028. &lt;/div&gt;
  2029. &lt;/div&gt;
  2030. &lt;div class=&quot;sect2&quot;&gt;
  2031. &lt;h3 id=&quot;choosing_the_jax_rs_implementation&quot;&gt;Choosing the JAX-RS implementation&lt;/h3&gt;
  2032. &lt;div class=&quot;paragraph&quot;&gt;
  2033. &lt;p&gt;Now we need to include any of the JAX-RS implementations in our module. Here is the relevant for your pom.xml:&lt;/p&gt;
  2034. &lt;/div&gt;
  2035. &lt;div class=&quot;listingblock&quot;&gt;
  2036. &lt;div class=&quot;title&quot;&gt;Apache CXF&lt;/div&gt;
  2037. &lt;div class=&quot;content&quot;&gt;
  2038. &lt;pre class=&quot;highlightjs highlight&quot;&gt;&lt;code class=&quot;language-xml hljs&quot; data-lang=&quot;xml&quot;&gt;    &amp;lt;dependency&amp;gt;
  2039.      &amp;lt;groupId&amp;gt;org.apache.cxf&amp;lt;/groupId&amp;gt;
  2040.      &amp;lt;artifactId&amp;gt;cxf-rt-rs-extension-providers&amp;lt;/artifactId&amp;gt;
  2041.      &amp;lt;version&amp;gt;${dependency.cxf.version}&amp;lt;/version&amp;gt;
  2042.      &amp;lt;scope&amp;gt;test&amp;lt;/scope&amp;gt;
  2043.    &amp;lt;/dependency&amp;gt;&lt;/code&gt;&lt;/pre&gt;
  2044. &lt;/div&gt;
  2045. &lt;/div&gt;
  2046. &lt;div class=&quot;paragraph&quot;&gt;
  2047. &lt;p&gt;or&lt;/p&gt;
  2048. &lt;/div&gt;
  2049. &lt;div class=&quot;listingblock&quot;&gt;
  2050. &lt;div class=&quot;title&quot;&gt;Eclipse Jersey&lt;/div&gt;
  2051. &lt;div class=&quot;content&quot;&gt;
  2052. &lt;pre class=&quot;highlightjs highlight&quot;&gt;&lt;code class=&quot;language-xml hljs&quot; data-lang=&quot;xml&quot;&gt;    &amp;lt;dependency&amp;gt;
  2053.      &amp;lt;groupId&amp;gt;org.glassfish.jersey.core&amp;lt;/groupId&amp;gt;
  2054.      &amp;lt;artifactId&amp;gt;jersey-server&amp;lt;/artifactId&amp;gt;
  2055.      &amp;lt;version&amp;gt;3.1.0-M8&amp;lt;/version&amp;gt;
  2056.      &amp;lt;scope&amp;gt;test&amp;lt;/scope&amp;gt;
  2057.    &amp;lt;/dependency&amp;gt;
  2058.  
  2059.    &amp;lt;dependency&amp;gt;
  2060.      &amp;lt;groupId&amp;gt;org.glassfish.jersey.core&amp;lt;/groupId&amp;gt;
  2061.      &amp;lt;artifactId&amp;gt;jersey-client&amp;lt;/artifactId&amp;gt;
  2062.      &amp;lt;version&amp;gt;3.1.0-M8&amp;lt;/version&amp;gt;
  2063.      &amp;lt;scope&amp;gt;test&amp;lt;/scope&amp;gt;
  2064.    &amp;lt;/dependency&amp;gt;
  2065.  
  2066.    &amp;lt;dependency&amp;gt;
  2067.      &amp;lt;groupId&amp;gt;org.glassfish.jersey.test-framework.providers&amp;lt;/groupId&amp;gt;
  2068.      &amp;lt;artifactId&amp;gt;jersey-test-framework-provider-grizzly2&amp;lt;/artifactId&amp;gt;
  2069.      &amp;lt;version&amp;gt;3.0.8&amp;lt;/version&amp;gt;
  2070.      &amp;lt;scope&amp;gt;test&amp;lt;/scope&amp;gt;
  2071.    &amp;lt;/dependency&amp;gt;
  2072.  
  2073.    &amp;lt;dependency&amp;gt;
  2074.      &amp;lt;groupId&amp;gt;org.glassfish.jersey.inject&amp;lt;/groupId&amp;gt;
  2075.      &amp;lt;artifactId&amp;gt;jersey-hk2&amp;lt;/artifactId&amp;gt;
  2076.      &amp;lt;version&amp;gt;3.1.0-M8&amp;lt;/version&amp;gt;
  2077.      &amp;lt;scope&amp;gt;test&amp;lt;/scope&amp;gt;
  2078.    &amp;lt;/dependency&amp;gt;&lt;/code&gt;&lt;/pre&gt;
  2079. &lt;/div&gt;
  2080. &lt;/div&gt;
  2081. &lt;div class=&quot;paragraph&quot;&gt;
  2082. &lt;p&gt;or&lt;/p&gt;
  2083. &lt;/div&gt;
  2084. &lt;div class=&quot;listingblock&quot;&gt;
  2085. &lt;div class=&quot;title&quot;&gt;JBoss RestEasy&lt;/div&gt;
  2086. &lt;div class=&quot;content&quot;&gt;
  2087. &lt;pre class=&quot;highlightjs highlight&quot;&gt;&lt;code class=&quot;language-xml hljs&quot; data-lang=&quot;xml&quot;&gt;&amp;lt;project&amp;gt;
  2088.  
  2089.  &amp;lt;properties&amp;gt;
  2090.    &amp;lt;version.org.jboss.resteasy&amp;gt;6.2.1.Final&amp;lt;/version.org.jboss.resteasy&amp;gt;
  2091.  &amp;lt;/properties&amp;gt;
  2092.  
  2093.  &amp;lt;dependencyManagement&amp;gt;
  2094.    &amp;lt;dependencies&amp;gt;
  2095.      &amp;lt;dependency&amp;gt;
  2096.        &amp;lt;groupId&amp;gt;org.jboss.resteasy&amp;lt;/groupId&amp;gt;
  2097.        &amp;lt;artifactId&amp;gt;resteasy-bom&amp;lt;/artifactId&amp;gt;
  2098.        &amp;lt;version&amp;gt;${version.org.jboss.resteasy}&amp;lt;/version&amp;gt;
  2099.        &amp;lt;type&amp;gt;pom&amp;lt;/type&amp;gt;
  2100.        &amp;lt;scope&amp;gt;import&amp;lt;/scope&amp;gt;
  2101.      &amp;lt;/dependency&amp;gt;
  2102.    &amp;lt;/dependencies&amp;gt;
  2103.  &amp;lt;/dependencyManagement&amp;gt;
  2104.  
  2105.  &amp;lt;dependencies&amp;gt;
  2106.    &amp;lt;dependency&amp;gt;
  2107.      &amp;lt;groupId&amp;gt;org.jboss.resteasy&amp;lt;/groupId&amp;gt;
  2108.      &amp;lt;artifactId&amp;gt;resteasy-undertow-cdi&amp;lt;/artifactId&amp;gt;
  2109.      &amp;lt;scope&amp;gt;test&amp;lt;/scope&amp;gt;
  2110.    &amp;lt;/dependency&amp;gt;
  2111.    &amp;lt;dependency&amp;gt;
  2112.      &amp;lt;groupId&amp;gt;org.jboss.resteasy&amp;lt;/groupId&amp;gt;
  2113.      &amp;lt;artifactId&amp;gt;resteasy-client&amp;lt;/artifactId&amp;gt;
  2114.      &amp;lt;scope&amp;gt;test&amp;lt;/scope&amp;gt;
  2115.    &amp;lt;/dependency&amp;gt;
  2116.  &amp;lt;/dependencies&amp;gt;
  2117.  
  2118.  &amp;lt;build&amp;gt;
  2119.    &amp;lt;plugins&amp;gt;
  2120.      &amp;lt;plugin&amp;gt;
  2121.        &amp;lt;groupId&amp;gt;org.jboss.jandex&amp;lt;/groupId&amp;gt;
  2122.        &amp;lt;artifactId&amp;gt;jandex-maven-plugin&amp;lt;/artifactId&amp;gt;
  2123.        &amp;lt;version&amp;gt;1.2.3&amp;lt;/version&amp;gt;
  2124.        &amp;lt;executions&amp;gt;
  2125.          &amp;lt;execution&amp;gt;
  2126.            &amp;lt;id&amp;gt;make-index&amp;lt;/id&amp;gt;
  2127.            &amp;lt;goals&amp;gt;
  2128.              &amp;lt;goal&amp;gt;jandex&amp;lt;/goal&amp;gt;
  2129.            &amp;lt;/goals&amp;gt;
  2130.          &amp;lt;/execution&amp;gt;
  2131.        &amp;lt;/executions&amp;gt;
  2132.      &amp;lt;/plugin&amp;gt;
  2133.    &amp;lt;/plugins&amp;gt;
  2134.  &amp;lt;/build&amp;gt;
  2135.  
  2136. &amp;lt;/project&amp;gt;&lt;/code&gt;&lt;/pre&gt;
  2137. &lt;/div&gt;
  2138. &lt;/div&gt;
  2139. &lt;div class=&quot;paragraph&quot;&gt;
  2140. &lt;p&gt;While those are the dependencies you need,
  2141. I haven‘t got my example working.
  2142. The dependencies are just shown for completeness.&lt;/p&gt;
  2143. &lt;/div&gt;
  2144. &lt;/div&gt;
  2145. &lt;div class=&quot;sect2&quot;&gt;
  2146. &lt;h3 id=&quot;adding_a_messagebodywriter&quot;&gt;Adding a MessageBodyWriter&lt;/h3&gt;
  2147. &lt;div class=&quot;paragraph&quot;&gt;
  2148. &lt;p&gt;Usually, this is done for you by your Application server.
  2149. However, in this case you will need to create your own MessageBodyWriter.&lt;/p&gt;
  2150. &lt;/div&gt;
  2151. &lt;div class=&quot;paragraph&quot;&gt;
  2152. &lt;p&gt;Instead of typing everything here, just copy parts of this module:
  2153. &lt;a href=&quot;https://github.com/bmarwell/jaxrs-test-showcase/tree/eb5765452bbd46505a5d2d5c44ea6945af698d89/systemtests/jaxrs-jsonb-support&quot;&gt;JAX-RS JSONB support&lt;/a&gt;.
  2154. This folder contains both a MessageBodyWriter and a JSONB context class.&lt;/p&gt;
  2155. &lt;/div&gt;
  2156. &lt;/div&gt;
  2157. &lt;/div&gt;
  2158. &lt;/div&gt;
  2159. &lt;div class=&quot;sect1&quot;&gt;
  2160. &lt;h2 id=&quot;implementing_tests&quot;&gt;Implementing tests&lt;/h2&gt;
  2161. &lt;div class=&quot;sectionbody&quot;&gt;
  2162. &lt;div class=&quot;paragraph&quot;&gt;
  2163. &lt;p&gt;Now that everything is set up, we can finally start writing tests!
  2164. I need to add: Writing tests for Jersey is both simpler and more straight forward.
  2165. Their dependency has everything included you will need, and you can use the default JaxRS &lt;code&gt;Client&lt;/code&gt; class.
  2166. For Apache CXF, you will want to write your own Junit Jupiter extension (no worries, I got you covered!) and you will be using their client whenever you chose local transport.&lt;/p&gt;
  2167. &lt;/div&gt;
  2168. &lt;div class=&quot;sect2&quot;&gt;
  2169. &lt;h3 id=&quot;eclipse_jersey_just_start_writing_tests&quot;&gt;Eclipse Jersey: Just start writing tests&lt;/h3&gt;
  2170. &lt;div class=&quot;paragraph&quot;&gt;
  2171. &lt;p&gt;With &lt;strong&gt;Eclipse Jersey&lt;/strong&gt;, it is really easy to start tests.
  2172. Once you added the correct dependency, it is just a matter of writing your tests.&lt;/p&gt;
  2173. &lt;/div&gt;
  2174. &lt;div class=&quot;paragraph&quot;&gt;
  2175. &lt;p&gt;Everything you need to do is to extend the &lt;code&gt;JerseyTest&lt;/code&gt; class, which is already in your class path. You will only need two additional methods, one of them encapsulated in a nested class like so:&lt;/p&gt;
  2176. &lt;/div&gt;
  2177. &lt;div class=&quot;listingblock&quot;&gt;
  2178. &lt;div class=&quot;title&quot;&gt;Setting up JerseyTest test classes&lt;/div&gt;
  2179. &lt;div class=&quot;content&quot;&gt;
  2180. &lt;pre class=&quot;highlightjs highlight&quot;&gt;&lt;code class=&quot;language-java hljs&quot; data-lang=&quot;java&quot;&gt;public class AuthorResourceTest extends JerseyTest {
  2181.  
  2182.  private static final JsonbContext jsonbContext = new JsonbContext();
  2183.  
  2184.  public static class ApplicationBinder extends AbstractBinder {
  2185.  
  2186.    @Override
  2187.    protected void configure() {
  2188.      bind(queryService).to(BookstoreQueryService.class).ranked(1);
  2189.      bind(AuthorMapper.class).to(AuthorMapper.class).ranked(1);
  2190.      bind(jsonbContext.getJsonb()).to(Jsonb.class);
  2191.    }
  2192.  }
  2193.  
  2194.  @Override
  2195.  protected Application configure() {
  2196.    // 0 == find first available port.
  2197.    forceSet(TestProperties.CONTAINER_PORT, &quot;0&quot;);
  2198.  
  2199.    return new ResourceConfig(AuthorResourceImpl.class)
  2200.        .register(new ApplicationBinder())
  2201.        .register(new JsonbJsonMessageBodyWriter());
  2202.  }
  2203. }&lt;/code&gt;&lt;/pre&gt;
  2204. &lt;/div&gt;
  2205. &lt;/div&gt;
  2206. &lt;div class=&quot;paragraph&quot;&gt;
  2207. &lt;p&gt;The inner static class &lt;code&gt;ApplicationBinder&lt;/code&gt; is used to configure injection - similar to what Google Guice does.
  2208. In the &lt;code&gt;configure()&lt;/code&gt; method, which is overridden from &lt;code&gt;JerseyTest&lt;/code&gt;, you can then use an instance of this class to make those bindings known to Jersey.
  2209. Please note I also register the MessageBodyWriter for JSON using our Jsonb implementation.&lt;/p&gt;
  2210. &lt;/div&gt;
  2211. &lt;div class=&quot;paragraph&quot;&gt;
  2212. &lt;p&gt;Now an actual test can be written in a similar way to what you do in unit tests:&lt;/p&gt;
  2213. &lt;/div&gt;
  2214. &lt;div class=&quot;listingblock&quot;&gt;
  2215. &lt;div class=&quot;title&quot;&gt;Writing JAX-RS test methods using JerseyTest&lt;/div&gt;
  2216. &lt;div class=&quot;content&quot;&gt;
  2217. &lt;pre class=&quot;highlightjs highlight&quot;&gt;&lt;code class=&quot;language-java hljs&quot; data-lang=&quot;java&quot;&gt;public class AuthorResourceTest extends JerseyTest {
  2218.  
  2219.  private static final BookstoreQueryService queryService = mock(BookstoreQueryService.class);
  2220.  
  2221.  @Test
  2222.  public void author_by_id_returns_author() {
  2223.    // given
  2224.    when(queryService.queryAuthors(any(AuthorQuery.class)))
  2225.        .then(args -&amp;gt; makeAnswerFromQuery(args.getArgument(0)));
  2226.  
  2227.    // when
  2228.    final Response authorByIdResponse = target(&quot;authors/rpfeynman&quot;)
  2229.        .request(MediaType.APPLICATION_JSON_TYPE)
  2230.        .get(Response.class);
  2231.  
  2232.    // then
  2233.    assertThat(authorByIdResponse)
  2234.        .hasFieldOrPropertyWithValue(&quot;status&quot;, 200)
  2235.        .extracting(rsp -&amp;gt; rsp.readEntity(String.class))
  2236.        .extracting(jsonStr -&amp;gt; jsonbContext.getJsonb().fromJson(jsonStr, Map.class))
  2237.        .hasFieldOrPropertyWithValue(&quot;id&quot;, &quot;rpfeynman&quot;);
  2238.  }
  2239. }&lt;/code&gt;&lt;/pre&gt;
  2240. &lt;/div&gt;
  2241. &lt;/div&gt;
  2242. &lt;div class=&quot;paragraph&quot;&gt;
  2243. &lt;p&gt;I omitted the method &lt;code&gt;makeAnswerFromQuery()&lt;/code&gt;, because it only sets up the mocked Service to return a useful result.&lt;/p&gt;
  2244. &lt;/div&gt;
  2245. &lt;div class=&quot;paragraph&quot;&gt;
  2246. &lt;p&gt;The test is using the standard JAX-RS Client API, which is good&amp;#8201;&amp;#8212;&amp;#8201;this is what Java clients should be using in production.
  2247. The assertion will check that the response completed successfully, then extracting the response and converting it back to a Java object.&lt;/p&gt;
  2248. &lt;/div&gt;
  2249. &lt;div class=&quot;paragraph&quot;&gt;
  2250. &lt;p&gt;You can find &lt;a href=&quot;https://github.com/bmarwell/jaxrs-test-showcase/blob/eb5765452bbd46505a5d2d5c44ea6945af698d89/systemtests/jersey-grizzly2-yasson/src/test/java/io/github/jaxrstesting/systemtests/jgy/AuthorResourceTest.java&quot;&gt;the complete example class on GitHub&lt;/a&gt;.&lt;/p&gt;
  2251. &lt;/div&gt;
  2252. &lt;/div&gt;
  2253. &lt;div class=&quot;sect2&quot;&gt;
  2254. &lt;h3 id=&quot;apache_cxf_writing_a_junit_jupiter_extension&quot;&gt;Apache CXF: Writing a Junit-Jupiter extension&lt;/h3&gt;
  2255. &lt;div class=&quot;paragraph&quot;&gt;
  2256. &lt;p&gt;First thing we need is an extension to make Apache CXF available to Junit.
  2257. The extension will manage the CXF server lifecycle as well as provide some methods to get an instance of the Apache CXF Client implementation.
  2258. The extension is written in a way that you can provide either instances or just the class - the extension will figure out how to instantiate resource classes under test.
  2259. Please note for simplicity, I only implemented &lt;code&gt;BeforeAllCallback, AfterAllCallback&lt;/code&gt;&amp;#8201;&amp;#8212;&amp;#8201;thus the server will start before ALL the tests and be shut down after ALL the tests were executed.&lt;/p&gt;
  2260. &lt;/div&gt;
  2261. &lt;div class=&quot;paragraph&quot;&gt;
  2262. &lt;p&gt;The extension will also register prodiers, features and resource classes and provides &lt;code&gt;.with*()&lt;/code&gt; methods for setting up those, which makes it very easy to use&amp;#8201;&amp;#8212;&amp;#8201;maybe even a bit easier than Eclipse Jersey.
  2263. As always, you can find &lt;a href=&quot;https://github.com/bmarwell/jaxrs-test-showcase/blob/eb5765452bbd46505a5d2d5c44ea6945af698d89/systemtests/cxf-localtp-junit-extension/src/main/java/io/github/jaxrstesting/systemtests/cxf/junit/CxfLocalTransportExtension.java&quot;&gt;the source code on GitHub&lt;/a&gt;.&lt;/p&gt;
  2264. &lt;/div&gt;
  2265. &lt;div class=&quot;paragraph&quot;&gt;
  2266. &lt;p&gt;Now with the extension set up, we can easily write our tests.&lt;/p&gt;
  2267. &lt;/div&gt;
  2268. &lt;div class=&quot;listingblock&quot;&gt;
  2269. &lt;div class=&quot;title&quot;&gt;Apache CXF base test class&lt;/div&gt;
  2270. &lt;div class=&quot;content&quot;&gt;
  2271. &lt;pre class=&quot;highlightjs highlight&quot;&gt;&lt;code class=&quot;language-java hljs&quot; data-lang=&quot;java&quot;&gt;public class AuthorResourceTest {
  2272.  
  2273.  private static final AuthorResourceImpl authorResource = new AuthorResourceImpl();
  2274.  
  2275.  private static final BookstoreQueryService queryService = mock(BookstoreQueryService.class);
  2276.  
  2277.  private static final AuthorMapper mapper = new AuthorMapper();
  2278.  
  2279.  private static final JsonbContext jsonbContext = new JsonbContext();
  2280.  
  2281.  
  2282.  @RegisterExtension
  2283.  static CxfLocalTransportExtension ltp = new CxfLocalTransportExtension()
  2284.      .withResource(AuthorResourceImpl.class, authorResource)
  2285.      .withProvider(new JsrJsonbProvider(jsonbContext.getJsonb()));
  2286.  
  2287.  @BeforeAll
  2288.  public static void setUpResource() {
  2289.    authorResource.setQueryService(queryService);
  2290.    authorResource.setAuthorMapper(mapper);
  2291.  }
  2292.  
  2293.  @AfterAll
  2294.  public static void closeJsonbContext() throws Exception {
  2295.    jsonbContext.close();
  2296.  }
  2297. }&lt;/code&gt;&lt;/pre&gt;
  2298. &lt;/div&gt;
  2299. &lt;/div&gt;
  2300. &lt;div class=&quot;paragraph&quot;&gt;
  2301. &lt;p&gt;As you can see, the set up is quite similar except that we use Junit-Jupiter‘s `@RegisterExtensionOther then that, ` annotation.&lt;/p&gt;
  2302. &lt;/div&gt;
  2303. &lt;div class=&quot;paragraph&quot;&gt;
  2304. &lt;p&gt;Now that this is set up, we can start writing tests the same way&amp;#8201;&amp;#8212;&amp;#8201;except that we need to use the Apache CXF client implementation:&lt;/p&gt;
  2305. &lt;/div&gt;
  2306. &lt;div class=&quot;listingblock&quot;&gt;
  2307. &lt;div class=&quot;title&quot;&gt;Writing Apache CXF system tests&lt;/div&gt;
  2308. &lt;div class=&quot;content&quot;&gt;
  2309. &lt;pre class=&quot;highlightjs highlight&quot;&gt;&lt;code class=&quot;language-java hljs&quot; data-lang=&quot;java&quot;&gt;public class AuthorResourceTest {
  2310.  
  2311.  @Test
  2312.  public void author_by_id_returns_author() {
  2313.    // given
  2314.    when(queryService.queryAuthors(any(AuthorQuery.class)))
  2315.        .then(args -&amp;gt; makeAnswerFromQuery(args.getArgument(0)));
  2316.  
  2317.    // when
  2318.    final Response authorByIdResponse = ltp.getWebClient()
  2319.        .accept(&quot;application/json&quot;)
  2320.        .path(&quot;authors/rpfeynman&quot;)
  2321.        .get();
  2322.  
  2323.    // then
  2324.    assertThat(authorByIdResponse)
  2325.        .hasFieldOrPropertyWithValue(&quot;status&quot;, 200)
  2326.        .extracting(rsp -&amp;gt; rsp.readEntity(String.class))
  2327.        .extracting(jsonStr -&amp;gt; jsonbContext.getJsonb().fromJson(jsonStr, Map.class))
  2328.        .hasFieldOrPropertyWithValue(&quot;id&quot;, &quot;rpfeynman&quot;);
  2329.  }
  2330. }&lt;/code&gt;&lt;/pre&gt;
  2331. &lt;/div&gt;
  2332. &lt;/div&gt;
  2333. &lt;div class=&quot;paragraph&quot;&gt;
  2334. &lt;p&gt;As you can see, the test class looks &lt;strong&gt;almost&lt;/strong&gt; identical, except that we do not use the JAX-RS client directly.&lt;/p&gt;
  2335. &lt;/div&gt;
  2336. &lt;/div&gt;
  2337. &lt;div class=&quot;sect2&quot;&gt;
  2338. &lt;h3 id=&quot;jboss_resteasy&quot;&gt;JBoss RestEasy&lt;/h3&gt;
  2339. &lt;div class=&quot;paragraph&quot;&gt;
  2340. &lt;p&gt;JBoss RestEasy can be tested using the &lt;code&gt;resteasy-undertow-cdi&lt;/code&gt; dependency.
  2341. Sadly, I was unable to get it running with CDI injection as of now.
  2342. Therefore, JBoss RestEasy system tests will be covered in a later article&lt;/p&gt;
  2343. &lt;/div&gt;
  2344. &lt;/div&gt;
  2345. &lt;/div&gt;
  2346. &lt;/div&gt;
  2347. &lt;div class=&quot;sect1&quot;&gt;
  2348. &lt;h2 id=&quot;outlook&quot;&gt;Outlook&lt;/h2&gt;
  2349. &lt;div class=&quot;sectionbody&quot;&gt;
  2350. &lt;div class=&quot;paragraph&quot;&gt;
  2351. &lt;p&gt;There is much more to testing JAX-RS applications than this guide could cover in a single article.
  2352. Later blog posts will cover:&lt;/p&gt;
  2353. &lt;/div&gt;
  2354. &lt;div class=&quot;ulist&quot;&gt;
  2355. &lt;ul&gt;
  2356. &lt;li&gt;
  2357. &lt;p&gt;Integration testing using various application servers, e.&amp;#160;g. Open&amp;#160;Liberty.&lt;/p&gt;
  2358. &lt;/li&gt;
  2359. &lt;li&gt;
  2360. &lt;p&gt;JBoss RestEasy system tests.&lt;/p&gt;
  2361. &lt;/li&gt;
  2362. &lt;li&gt;
  2363. &lt;p&gt;Apache Shiro integration.&lt;/p&gt;
  2364. &lt;/li&gt;
  2365. &lt;li&gt;
  2366. &lt;p&gt;&amp;#8230;&amp;#8203; you tell me! :)&lt;/p&gt;
  2367. &lt;/li&gt;
  2368. &lt;/ul&gt;
  2369. &lt;/div&gt;
  2370. &lt;/div&gt;
  2371. &lt;/div&gt;
  2372. &lt;div class=&quot;sect1&quot;&gt;
  2373. &lt;h2 id=&quot;references&quot;&gt;References&lt;/h2&gt;
  2374. &lt;div class=&quot;sectionbody&quot;&gt;
  2375. &lt;div class=&quot;ulist&quot;&gt;
  2376. &lt;ul&gt;
  2377. &lt;li&gt;
  2378. &lt;p&gt;Full example project ib GitHub:&lt;br&gt;
  2379. &lt;a href=&quot;https://github.com/bmarwell/jaxrs-test-showcase&quot;&gt;github.com/bmarwell/jaxrs-test/showcase&lt;/a&gt;&lt;/p&gt;
  2380. &lt;/li&gt;
  2381. &lt;li&gt;
  2382. &lt;p&gt;Eclipse Jersey: Test Framework:&lt;br&gt;
  2383. &lt;a href=&quot;https://eclipse-ee4j.github.io/jersey.github.io/documentation/latest/test-framework.html&quot; class=&quot;bare&quot;&gt;https://eclipse-ee4j.github.io/jersey.github.io/documentation/latest/test-framework.html&lt;/a&gt;&lt;/p&gt;
  2384. &lt;/li&gt;
  2385. &lt;li&gt;
  2386. &lt;p&gt;Apache CXF: JAX-RS Testing:&lt;br&gt;
  2387. &lt;a href=&quot;https://cwiki.apache.org/confluence/display/CXF20DOC/JAXRS+Testing&quot; class=&quot;bare&quot;&gt;https://cwiki.apache.org/confluence/display/CXF20DOC/JAXRS+Testing&lt;/a&gt;&lt;/p&gt;
  2388. &lt;/li&gt;
  2389. &lt;li&gt;
  2390. &lt;p&gt;Apache CXF: Local Transport:&lt;br&gt;
  2391. &lt;a href=&quot;https://cxf.apache.org/docs/local-transport.html&quot; class=&quot;bare&quot;&gt;https://cxf.apache.org/docs/local-transport.html&lt;/a&gt;&lt;/p&gt;
  2392. &lt;/li&gt;
  2393. &lt;li&gt;
  2394. &lt;p&gt;RestEasy: bootstrap-cdi example:&lt;br&gt;
  2395. &lt;a href=&quot;https://github.com/resteasy/resteasy-quickstarts/pull/2/files&quot; class=&quot;bare&quot;&gt;https://github.com/resteasy/resteasy-quickstarts/pull/2/files&lt;/a&gt;&lt;/p&gt;
  2396. &lt;/li&gt;
  2397. &lt;/ul&gt;
  2398. &lt;/div&gt;
  2399. &lt;/div&gt;
  2400. &lt;/div&gt;
  2401.    </content>
  2402.  </entry>
  2403.  
  2404.  <entry>
  2405.    <!-- lang="en-GB"  -->
  2406.    <title>Guide: How to develop an Open Liberty Feature</title>
  2407.    <link href="https://blog.bmarwell.de/2022/06/10/developing-an-openliberty-feature.html"/>
  2408.    <id>https://blog.bmarwell.de/2022/06/10/developing-an-openliberty-feature.html</id>
  2409.    <published>2022-06-10T20:00:35Z</published>
  2410.    <updated>2022-06-10T20:00:35Z</updated>
  2411.    <author>
  2412.      <name>Benjamin Marwell</name>
  2413.    </author>
  2414.    <content type="html">
  2415.      &lt;div id=&quot;preamble&quot;&gt;
  2416. &lt;div class=&quot;sectionbody&quot;&gt;
  2417. &lt;div class=&quot;paragraph&quot;&gt;
  2418. &lt;p&gt;Developing User Features for &lt;strong&gt;Open Liberty&lt;/strong&gt; can be a very interesting project.
  2419. &lt;a href=&quot;https://openliberty.io&quot;&gt;Open Liberty&lt;/a&gt; is very extensible.
  2420. Sadly, the documentation only exists for &lt;a href=&quot;https://www.ibm.com/support/pages/websphere-liberty-developers&quot;&gt;IBM WebSphere Liberty&lt;/a&gt; and requires a lot of prior knowledge.
  2421. It does not even mention build tools like Apache Ant, Apache Maven or Gradle at all.&lt;/p&gt;
  2422. &lt;/div&gt;
  2423. &lt;div class=&quot;paragraph&quot;&gt;
  2424. &lt;p&gt;This guide will get you started so you can develop your own features.
  2425. I will also provide a demo project.&lt;/p&gt;
  2426. &lt;/div&gt;
  2427. &lt;div id=&quot;toc&quot; class=&quot;toc&quot;&gt;
  2428. &lt;div id=&quot;toctitle&quot; class=&quot;title&quot;&gt;Table of Contents&lt;/div&gt;
  2429. &lt;ul class=&quot;sectlevel1&quot;&gt;
  2430. &lt;li&gt;&lt;a href=&quot;#get_me_straight_to_the_code&quot;&gt;Get me straight to the code!&lt;/a&gt;
  2431. &lt;ul class=&quot;sectlevel2&quot;&gt;
  2432. &lt;li&gt;&lt;a href=&quot;#server_xml&quot;&gt;server.xml&lt;/a&gt;&lt;/li&gt;
  2433. &lt;li&gt;&lt;a href=&quot;#example_output&quot;&gt;Example output&lt;/a&gt;&lt;/li&gt;
  2434. &lt;/ul&gt;
  2435. &lt;/li&gt;
  2436. &lt;li&gt;&lt;a href=&quot;#maven_module_layout&quot;&gt;Maven module layout&lt;/a&gt;&lt;/li&gt;
  2437. &lt;li&gt;&lt;a href=&quot;#minimum_files_in_the_bundle_project&quot;&gt;Minimum files in the bundle project&lt;/a&gt;
  2438. &lt;ul class=&quot;sectlevel2&quot;&gt;
  2439. &lt;li&gt;&lt;a href=&quot;#setting_up_a_typebundle_maven_project&quot;&gt;Setting up a type=bundle maven project&lt;/a&gt;&lt;/li&gt;
  2440. &lt;li&gt;&lt;a href=&quot;#activator_class&quot;&gt;Activator class&lt;/a&gt;
  2441. &lt;ul class=&quot;sectlevel3&quot;&gt;
  2442. &lt;li&gt;&lt;a href=&quot;#implementing_the_start_method&quot;&gt;Implementing the &lt;code&gt;start()&lt;/code&gt; method&lt;/a&gt;&lt;/li&gt;
  2443. &lt;li&gt;&lt;a href=&quot;#implementing_the_stop_method&quot;&gt;Implementing the &lt;code&gt;stop()&lt;/code&gt; method&lt;/a&gt;&lt;/li&gt;
  2444. &lt;li&gt;&lt;a href=&quot;#implementing_the_updated_method&quot;&gt;Implementing the &lt;code&gt;updated()&lt;/code&gt; method&lt;/a&gt;&lt;/li&gt;
  2445. &lt;/ul&gt;
  2446. &lt;/li&gt;
  2447. &lt;li&gt;&lt;a href=&quot;#bundle_description&quot;&gt;Bundle description&lt;/a&gt;&lt;/li&gt;
  2448. &lt;/ul&gt;
  2449. &lt;/li&gt;
  2450. &lt;li&gt;&lt;a href=&quot;#setting_up_the_open_liberty_feature_definition&quot;&gt;Setting up the Open Liberty feature definition&lt;/a&gt;
  2451. &lt;ul class=&quot;sectlevel2&quot;&gt;
  2452. &lt;li&gt;&lt;a href=&quot;#creating_an_esa_output_file&quot;&gt;Creating an &lt;code&gt;.esa&lt;/code&gt; output file&lt;/a&gt;&lt;/li&gt;
  2453. &lt;li&gt;&lt;a href=&quot;#prettier_version_numbers&quot;&gt;Prettier version numbers&lt;/a&gt;&lt;/li&gt;
  2454. &lt;li&gt;&lt;a href=&quot;#writing_the_esa_manifest&quot;&gt;Writing the &lt;code&gt;.esa&lt;/code&gt; manifest&lt;/a&gt;&lt;/li&gt;
  2455. &lt;/ul&gt;
  2456. &lt;/li&gt;
  2457. &lt;li&gt;&lt;a href=&quot;#installing_the_feature&quot;&gt;Installing the feature&lt;/a&gt;
  2458. &lt;ul class=&quot;sectlevel2&quot;&gt;
  2459. &lt;li&gt;&lt;a href=&quot;#building_the_project&quot;&gt;Building the project&lt;/a&gt;&lt;/li&gt;
  2460. &lt;li&gt;&lt;a href=&quot;#using_featuremanager_on_ibm_websphere_liberty_profile&quot;&gt;Using &lt;code&gt;featureManager&lt;/code&gt; on IBM WebSphere Liberty Profile&lt;/a&gt;&lt;/li&gt;
  2461. &lt;li&gt;&lt;a href=&quot;#using_featuremanager_on_open_liberty&quot;&gt;Using &lt;code&gt;featureManager&lt;/code&gt; on Open Liberty&lt;/a&gt;&lt;/li&gt;
  2462. &lt;li&gt;&lt;a href=&quot;#installing_the_feature_manually&quot;&gt;Installing the feature manually&lt;/a&gt;&lt;/li&gt;
  2463. &lt;/ul&gt;
  2464. &lt;/li&gt;
  2465. &lt;li&gt;&lt;a href=&quot;#where_to_go_from_here&quot;&gt;Where to go from here&lt;/a&gt;&lt;/li&gt;
  2466. &lt;/ul&gt;
  2467. &lt;/div&gt;
  2468. &lt;/div&gt;
  2469. &lt;/div&gt;
  2470. &lt;div class=&quot;sect1&quot;&gt;
  2471. &lt;h2 id=&quot;get_me_straight_to_the_code&quot;&gt;Get me straight to the code!&lt;/h2&gt;
  2472. &lt;div class=&quot;sectionbody&quot;&gt;
  2473. &lt;div class=&quot;paragraph&quot;&gt;
  2474. &lt;p&gt;OK, here it is: &lt;a href=&quot;https://github.com/bmarwell/cowsay-liberty-feature-showcase&quot; class=&quot;bare&quot;&gt;https://github.com/bmarwell/cowsay-liberty-feature-showcase&lt;/a&gt;&lt;/p&gt;
  2475. &lt;/div&gt;
  2476. &lt;div class=&quot;paragraph&quot;&gt;
  2477. &lt;p&gt;The &lt;strong&gt;cowsay-liberty-feature-showcase&lt;/strong&gt; is a minimal feature for Open Liberty.
  2478. Configuration and everything from below is used to show how to set up a Liberty feature.&lt;/p&gt;
  2479. &lt;/div&gt;
  2480. &lt;div class=&quot;paragraph&quot;&gt;
  2481. &lt;p&gt;&lt;strong&gt;Description:&lt;/strong&gt;&lt;br&gt;
  2482. This feature will implement the famous &quot;cowsay&quot; on startup like so:&lt;/p&gt;
  2483. &lt;/div&gt;
  2484. &lt;div class=&quot;sect2&quot;&gt;
  2485. &lt;h3 id=&quot;server_xml&quot;&gt;server.xml&lt;/h3&gt;
  2486. &lt;div class=&quot;listingblock&quot;&gt;
  2487. &lt;div class=&quot;title&quot;&gt;A minimal cowsay &lt;code&gt;server.xml&lt;/code&gt; setup&lt;/div&gt;
  2488. &lt;div class=&quot;content&quot;&gt;
  2489. &lt;pre class=&quot;highlightjs highlight&quot;&gt;&lt;code class=&quot;language-xml hljs&quot; data-lang=&quot;xml&quot;&gt;&amp;lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&amp;gt;
  2490. &amp;lt;server description=&quot;cowsay&quot;&amp;gt;
  2491.  &amp;lt;featureManager&amp;gt;
  2492.    &amp;lt;feature&amp;gt;usr:cowsay-1.0&amp;lt;/feature&amp;gt;
  2493.  &amp;lt;/featureManager&amp;gt;
  2494.  
  2495.  &amp;lt;cowsay message=&quot;Hello, Liberty&quot; /&amp;gt;
  2496. &amp;lt;/server&amp;gt;&lt;/code&gt;&lt;/pre&gt;
  2497. &lt;/div&gt;
  2498. &lt;/div&gt;
  2499. &lt;/div&gt;
  2500. &lt;div class=&quot;sect2&quot;&gt;
  2501. &lt;h3 id=&quot;example_output&quot;&gt;Example output&lt;/h3&gt;
  2502. &lt;div class=&quot;listingblock&quot;&gt;
  2503. &lt;div class=&quot;content&quot;&gt;
  2504. &lt;pre class=&quot;highlightjs highlight&quot;&gt;&lt;code class=&quot;language-none hljs&quot;&gt;Launching defaultServer (WebSphere Application Server 22.0.0.5/wlp-1.0.64.cl220520220425-0301) on OpenJDK 64-Bit Server VM, version 1.8.0_332-b09 (en_US)
  2505. [AUDIT   ] CWWKE0001I: The server defaultServer has been launched.
  2506. [AUDIT   ] CWWKE0100I: This product is licensed for development, and limited production use. The full license terms can be viewed here: https://public.dhe.ibm.com/ibmdl/export/pub/software/websphere/wasdev/license/base_ilan/ilan/22.0.0.5/lafiles/en.html
  2507. [INFO    ] CWWKE0002I: The kernel started after 0.544 seconds
  2508. [INFO    ] CWWKF0007I: Feature update started.
  2509. [ERROR   ] COWSA0001I:  ________________
  2510. [ERROR   ] COWSA0001I: &amp;lt; Hello, Liberty &amp;gt;
  2511. [ERROR   ] COWSA0001I:  ----------------
  2512. [ERROR   ] COWSA0001I:         \   ^__^
  2513. [ERROR   ] COWSA0001I:          \  (oo)\_______
  2514. [ERROR   ] COWSA0001I:             (__)\       )\/\
  2515. [ERROR   ] COWSA0001I:                 ||----w |
  2516. [ERROR   ] COWSA0001I:                 ||     ||
  2517. [AUDIT   ] CWWKF0012I: The server installed the following features: [usr:cowsay-1.0].
  2518. [INFO    ] CWWKF0008I: Feature update completed in 0.075 seconds.
  2519. [AUDIT   ] CWWKF0011I: The defaultServer server is ready to run a smarter planet. The defaultServer server started in 0.620 seconds.&lt;/code&gt;&lt;/pre&gt;
  2520. &lt;/div&gt;
  2521. &lt;/div&gt;
  2522. &lt;/div&gt;
  2523. &lt;/div&gt;
  2524. &lt;/div&gt;
  2525. &lt;div class=&quot;sect1&quot;&gt;
  2526. &lt;h2 id=&quot;maven_module_layout&quot;&gt;Maven module layout&lt;/h2&gt;
  2527. &lt;div class=&quot;sectionbody&quot;&gt;
  2528. &lt;div class=&quot;paragraph&quot;&gt;
  2529. &lt;p&gt;First of all, we need a maven reactor project with some modules.
  2530. The minimum setup is:&lt;/p&gt;
  2531. &lt;/div&gt;
  2532. &lt;div class=&quot;listingblock&quot;&gt;
  2533. &lt;div class=&quot;content&quot;&gt;
  2534. &lt;pre class=&quot;highlightjs highlight&quot;&gt;&lt;code class=&quot;language-none hljs&quot;&gt;pom.xml
  2535. |- bundle
  2536. |  ` pom.xml
  2537. `- feature
  2538.   ` pom.xml&lt;/code&gt;&lt;/pre&gt;
  2539. &lt;/div&gt;
  2540. &lt;/div&gt;
  2541. &lt;div class=&quot;paragraph&quot;&gt;
  2542. &lt;p&gt;In other words: We need to define three modules:&lt;/p&gt;
  2543. &lt;/div&gt;
  2544. &lt;div class=&quot;dlist&quot;&gt;
  2545. &lt;dl&gt;
  2546. &lt;dt class=&quot;hdlist1&quot;&gt;root&lt;/dt&gt;
  2547. &lt;dd&gt;
  2548. &lt;p&gt;The reactor root project.&lt;/p&gt;
  2549. &lt;/dd&gt;
  2550. &lt;dt class=&quot;hdlist1&quot;&gt;bundle&lt;/dt&gt;
  2551. &lt;dd&gt;
  2552. &lt;p&gt;The jar file containing the OSGi module and the Java code.&lt;/p&gt;
  2553. &lt;/dd&gt;
  2554. &lt;dt class=&quot;hdlist1&quot;&gt;feature&lt;/dt&gt;
  2555. &lt;dd&gt;
  2556. &lt;p&gt;The feature description and &lt;code&gt;.esa&lt;/code&gt; packaging.&lt;/p&gt;
  2557. &lt;/dd&gt;
  2558. &lt;/dl&gt;
  2559. &lt;/div&gt;
  2560. &lt;div class=&quot;paragraph&quot;&gt;
  2561. &lt;p&gt;We &lt;strong&gt;could&lt;/strong&gt; combine them into one project in theory, but I find one-module-per-use-case far more helpful when writing tests.
  2562. E.g. the bundle module could easily be tested within an integration test module.&lt;/p&gt;
  2563. &lt;/div&gt;
  2564. &lt;/div&gt;
  2565. &lt;/div&gt;
  2566. &lt;div class=&quot;sect1&quot;&gt;
  2567. &lt;h2 id=&quot;minimum_files_in_the_bundle_project&quot;&gt;Minimum files in the bundle project&lt;/h2&gt;
  2568. &lt;div class=&quot;sectionbody&quot;&gt;
  2569. &lt;div class=&quot;paragraph&quot;&gt;
  2570. &lt;p&gt;Since this is a bundle project, you will at least set up the maven reactor project as a bundle type.&lt;/p&gt;
  2571. &lt;/div&gt;
  2572. &lt;div class=&quot;sect2&quot;&gt;
  2573. &lt;h3 id=&quot;setting_up_a_typebundle_maven_project&quot;&gt;Setting up a type=bundle maven project&lt;/h3&gt;
  2574. &lt;div class=&quot;paragraph&quot;&gt;
  2575. &lt;p&gt;In your &lt;code&gt;bundle/pom.xml&lt;/code&gt;, set the type to »bundle« using &lt;code&gt;&amp;lt;type&amp;gt;bundle&amp;lt;/type&amp;gt;&lt;/code&gt;.
  2576. For this type to be recognized, setup the appropriate plugin as well:&lt;/p&gt;
  2577. &lt;/div&gt;
  2578. &lt;div class=&quot;listingblock&quot;&gt;
  2579. &lt;div class=&quot;title&quot;&gt;Defining a bundle project&lt;/div&gt;
  2580. &lt;div class=&quot;content&quot;&gt;
  2581. &lt;pre class=&quot;highlightjs highlight&quot;&gt;&lt;code class=&quot;language-xml hljs&quot; data-lang=&quot;xml&quot;&gt;  &amp;lt;build&amp;gt;
  2582.    &amp;lt;plugins&amp;gt;
  2583.      &amp;lt;plugin&amp;gt;
  2584.        &amp;lt;groupId&amp;gt;org.apache.felix&amp;lt;/groupId&amp;gt;
  2585.        &amp;lt;artifactId&amp;gt;maven-bundle-plugin&amp;lt;/artifactId&amp;gt;
  2586.        &amp;lt;extensions&amp;gt;true&amp;lt;/extensions&amp;gt;
  2587.      &amp;lt;/plugin&amp;gt;
  2588.    &amp;lt;/plugins&amp;gt;
  2589.  &amp;lt;/build&amp;gt;&lt;/code&gt;&lt;/pre&gt;
  2590. &lt;/div&gt;
  2591. &lt;/div&gt;
  2592. &lt;div class=&quot;paragraph&quot;&gt;
  2593. &lt;p&gt;Explanation:&lt;/p&gt;
  2594. &lt;/div&gt;
  2595. &lt;div class=&quot;dlist&quot;&gt;
  2596. &lt;dl&gt;
  2597. &lt;dt class=&quot;hdlist1&quot;&gt;extensions&lt;/dt&gt;
  2598. &lt;dd&gt;
  2599. &lt;p&gt;Setting this to &lt;code&gt;true&lt;/code&gt; will enable maven to build a &lt;code&gt;bundle&lt;/code&gt; type project (i.e. recognize the &lt;code&gt;&amp;lt;type&amp;gt;bundle&amp;lt;/type&amp;gt;&lt;/code&gt; directive).&lt;/p&gt;
  2600. &lt;/dd&gt;
  2601. &lt;/dl&gt;
  2602. &lt;/div&gt;
  2603. &lt;/div&gt;
  2604. &lt;div class=&quot;sect2&quot;&gt;
  2605. &lt;h3 id=&quot;activator_class&quot;&gt;Activator class&lt;/h3&gt;
  2606. &lt;div class=&quot;paragraph&quot;&gt;
  2607. &lt;p&gt;You will need some Java code which is going to be executed at SOME point during the Open Liberty runtime.
  2608. The entry point is a class usually called &lt;code&gt;Activator&lt;/code&gt; (or &lt;code&gt;MyFeatureActivator&lt;/code&gt; or similar) implementing both &lt;code&gt;org.osgi.framework.BundleActivator&lt;/code&gt; and &lt;code&gt;org.osgi.service.cm.ManagedService&lt;/code&gt;.
  2609. The &lt;code&gt;BundleActivator&lt;/code&gt; will introduce start and stop methods, while the &lt;code&gt;ManagedService&lt;/code&gt; will provide an update mechanism (i.e. changed configuration during the runtime).&lt;/p&gt;
  2610. &lt;/div&gt;
  2611. &lt;div class=&quot;paragraph&quot;&gt;
  2612. &lt;p&gt;I will skip the description of the methods &lt;code&gt;emitStartMessage()&lt;/code&gt; and&lt;/p&gt;
  2613. &lt;/div&gt;
  2614. &lt;div class=&quot;sect3&quot;&gt;
  2615. &lt;h4 id=&quot;implementing_the_start_method&quot;&gt;Implementing the &lt;code&gt;start()&lt;/code&gt; method&lt;/h4&gt;
  2616. &lt;div class=&quot;paragraph&quot;&gt;
  2617. &lt;p&gt;The start method will be executed on activation, obviously.
  2618. The only thing you need is a registration call:&lt;/p&gt;
  2619. &lt;/div&gt;
  2620. &lt;div class=&quot;listingblock&quot;&gt;
  2621. &lt;div class=&quot;content&quot;&gt;
  2622. &lt;pre class=&quot;highlightjs highlight&quot;&gt;&lt;code class=&quot;language-java hljs&quot; data-lang=&quot;java&quot;&gt;  @Override
  2623.  public void start(BundleContext context) throws Exception {
  2624.    configRef = context.registerService(ManagedService.class, this, this.getConfigDefaults());
  2625.  }
  2626.  
  2627.  protected Dictionary&amp;lt;String, ?&amp;gt; getConfigDefaults() {
  2628.    Hashtable&amp;lt;String, Object&amp;gt; configDefaults = new Hashtable&amp;lt;&amp;gt;();
  2629.    configDefaults.put(org.osgi.framework.Constants.SERVICE_PID, &quot;cowsay&quot;);
  2630.  
  2631.    return configDefaults;
  2632.  }&lt;/code&gt;&lt;/pre&gt;
  2633. &lt;/div&gt;
  2634. &lt;/div&gt;
  2635. &lt;div class=&quot;paragraph&quot;&gt;
  2636. &lt;p&gt;The 2nd method is almost copied from the docs.
  2637. It sets the service PID, which is the configuration tag name in your &lt;code&gt;server.xml&lt;/code&gt;.&lt;/p&gt;
  2638. &lt;/div&gt;
  2639. &lt;/div&gt;
  2640. &lt;div class=&quot;sect3&quot;&gt;
  2641. &lt;h4 id=&quot;implementing_the_stop_method&quot;&gt;Implementing the &lt;code&gt;stop()&lt;/code&gt; method&lt;/h4&gt;
  2642. &lt;div class=&quot;paragraph&quot;&gt;
  2643. &lt;p&gt;As we do not implement a &quot;stop message&quot; in this showcase feature, we just need to unregister the service.&lt;/p&gt;
  2644. &lt;/div&gt;
  2645. &lt;div class=&quot;listingblock&quot;&gt;
  2646. &lt;div class=&quot;content&quot;&gt;
  2647. &lt;pre class=&quot;highlightjs highlight&quot;&gt;&lt;code class=&quot;language-java hljs&quot; data-lang=&quot;java&quot;&gt;  @Override
  2648.  public void stop(BundleContext context) throws Exception {
  2649.    this.configRef.unregister();
  2650.  }&lt;/code&gt;&lt;/pre&gt;
  2651. &lt;/div&gt;
  2652. &lt;/div&gt;
  2653. &lt;/div&gt;
  2654. &lt;div class=&quot;sect3&quot;&gt;
  2655. &lt;h4 id=&quot;implementing_the_updated_method&quot;&gt;Implementing the &lt;code&gt;updated()&lt;/code&gt; method&lt;/h4&gt;
  2656. &lt;div class=&quot;paragraph&quot;&gt;
  2657. &lt;p&gt;Now this is the method which is called when the configuration gets updated.
  2658. Caveat: It seems to get called AFTER the start method, but I have seen overlapping calls of those methods as well.&lt;/p&gt;
  2659. &lt;/div&gt;
  2660. &lt;div class=&quot;paragraph&quot;&gt;
  2661. &lt;p&gt;I implemented it in a way that there is one cowsay call after reading in the variables&amp;#8201;&amp;#8212;&amp;#8201;if set.
  2662. Since there is no further check, any configuration update will also trigger a &quot;moo&quot;.&lt;/p&gt;
  2663. &lt;/div&gt;
  2664. &lt;div class=&quot;listingblock&quot;&gt;
  2665. &lt;div class=&quot;content&quot;&gt;
  2666. &lt;pre class=&quot;highlightjs highlight&quot;&gt;&lt;code class=&quot;language-java hljs&quot; data-lang=&quot;java&quot;&gt; @Override
  2667.  public void updated(Dictionary&amp;lt;String, ?&amp;gt; properties) throws ConfigurationException {
  2668.    if (properties == null) {
  2669.      return;
  2670.    }
  2671.  
  2672.    Object cowfile = properties.get(&quot;cowfile&quot;);
  2673.    if (cowfile instanceof String) {
  2674.      this.cowfile = (String) cowfile;
  2675.    }
  2676.  
  2677.    Object message = properties.get(&quot;message&quot;);
  2678.    if (message instanceof String) {
  2679.      this.message = (String) message;
  2680.    }
  2681.  
  2682.    emitStartMessage();
  2683.  }&lt;/code&gt;&lt;/pre&gt;
  2684. &lt;/div&gt;
  2685. &lt;/div&gt;
  2686. &lt;/div&gt;
  2687. &lt;/div&gt;
  2688. &lt;div class=&quot;sect2&quot;&gt;
  2689. &lt;h3 id=&quot;bundle_description&quot;&gt;Bundle description&lt;/h3&gt;
  2690. &lt;div class=&quot;paragraph&quot;&gt;
  2691. &lt;p&gt;We will need to add a manifest description OSGi can read.
  2692. We can either write it into a file, but I find XML in this case much more useful.
  2693. IDEs will usually help you with completion, and you can more easily use maven properties here (without configuring filtered resources).&lt;/p&gt;
  2694. &lt;/div&gt;
  2695. &lt;div class=&quot;listingblock&quot;&gt;
  2696. &lt;div class=&quot;title&quot;&gt;The updated &lt;code&gt;bundle/pom.xml&lt;/code&gt;&lt;/div&gt;
  2697. &lt;div class=&quot;content&quot;&gt;
  2698. &lt;pre class=&quot;highlightjs highlight&quot;&gt;&lt;code class=&quot;language-xml hljs&quot; data-lang=&quot;xml&quot;&gt;  &amp;lt;build&amp;gt;
  2699.    &amp;lt;plugins&amp;gt;
  2700.      &amp;lt;plugin&amp;gt;
  2701.        &amp;lt;groupId&amp;gt;org.apache.felix&amp;lt;/groupId&amp;gt;
  2702.        &amp;lt;artifactId&amp;gt;maven-bundle-plugin&amp;lt;/artifactId&amp;gt;
  2703.        &amp;lt;extensions&amp;gt;true&amp;lt;/extensions&amp;gt;
  2704.        &amp;lt;configuration&amp;gt;
  2705.          &amp;lt;instructions&amp;gt;
  2706.            &amp;lt;Import-Package&amp;gt;
  2707.              org.osgi.framework,
  2708.              org.osgi.service.cm
  2709.            &amp;lt;/Import-Package&amp;gt;
  2710.            &amp;lt;Embed-Dependency&amp;gt;*;scope=compile|runtime&amp;lt;/Embed-Dependency&amp;gt;
  2711.            &amp;lt;Embed-Transitive&amp;gt;true&amp;lt;/Embed-Transitive&amp;gt;
  2712.            &amp;lt;Export-Package&amp;gt;io.github.bmarwell.liberty.cowsay&amp;lt;/Export-Package&amp;gt;
  2713.            &amp;lt;Private-Package&amp;gt;io.github.bmarwell.liberty.cowsay.*&amp;lt;/Private-Package&amp;gt;
  2714.            &amp;lt;Bundle-Activator&amp;gt;io.github.bmarwell.liberty.cowsay.Activator&amp;lt;/Bundle-Activator&amp;gt;
  2715.            &amp;lt;!--
  2716.              &amp;lt;Bundle-Version&amp;gt; is assumed to be &quot;${pom.version}&quot;,
  2717.              but is normalized to the OSGi version format of &quot;MAJOR.MINOR.MICRO.QUALIFIER&quot;.
  2718.              For example &quot;2.1-SNAPSHOT&quot; would become &quot;2.1.0.SNAPSHOT&quot;.
  2719.              https://felix.apache.org/documentation/subprojects/apache-felix-maven-bundle-plugin-bnd.html
  2720.            --&amp;gt;
  2721.            &amp;lt;Bundle-RequiredExecutionEnvironment&amp;gt;JavaSE-1.8&amp;lt;/Bundle-RequiredExecutionEnvironment&amp;gt;
  2722.          &amp;lt;/instructions&amp;gt;
  2723.        &amp;lt;/configuration&amp;gt;
  2724.      &amp;lt;/plugin&amp;gt;
  2725.    &amp;lt;/plugins&amp;gt;
  2726.  &amp;lt;/build&amp;gt;&lt;/code&gt;&lt;/pre&gt;
  2727. &lt;/div&gt;
  2728. &lt;/div&gt;
  2729. &lt;div class=&quot;admonitionblock warning&quot;&gt;
  2730. &lt;table&gt;
  2731. &lt;tr&gt;
  2732. &lt;td class=&quot;icon&quot;&gt;
  2733. &lt;i class=&quot;fa icon-warning&quot; title=&quot;Warning&quot;&gt;&lt;/i&gt;
  2734. &lt;/td&gt;
  2735. &lt;td class=&quot;content&quot;&gt;
  2736. &lt;div class=&quot;title&quot;&gt;Bundle lazy loading&lt;/div&gt;
  2737. &lt;div class=&quot;paragraph&quot;&gt;
  2738. &lt;p&gt;Do &lt;strong&gt;NOT&lt;/strong&gt; activate lazy loading.
  2739. This will result in (Open) Liberty not executing your feature AT ALL!&lt;/p&gt;
  2740. &lt;/div&gt;
  2741. &lt;/td&gt;
  2742. &lt;/tr&gt;
  2743. &lt;/table&gt;
  2744. &lt;/div&gt;
  2745. &lt;div class=&quot;paragraph&quot;&gt;
  2746. &lt;p&gt;Explanation of what we added:&lt;/p&gt;
  2747. &lt;/div&gt;
  2748. &lt;div class=&quot;dlist&quot;&gt;
  2749. &lt;dl&gt;
  2750. &lt;dt class=&quot;hdlist1&quot;&gt;Import-Package&lt;/dt&gt;
  2751. &lt;dd&gt;
  2752. &lt;p&gt;Here, all used imports from dependencies need to be declared on a package level.
  2753. The bundle-plugin will create this list for you.&lt;br&gt;&lt;/p&gt;
  2754. &lt;div class=&quot;paragraph&quot;&gt;
  2755. &lt;p&gt;&lt;strong&gt;HOWEVER&lt;/strong&gt;.&lt;br&gt;
  2756. If any of your dependencies is not an OSGi bundle, this will fail.
  2757. In this case, just add the packages you are using like in the example above.&lt;/p&gt;
  2758. &lt;/div&gt;
  2759. &lt;/dd&gt;
  2760. &lt;dt class=&quot;hdlist1&quot;&gt;Embed-Dependency&lt;/dt&gt;
  2761. &lt;dd&gt;
  2762. &lt;p&gt;We will need to bring all dependencies in our bundle, because we cannot do that in our &lt;code&gt;.esa&lt;/code&gt; file easily.
  2763. This will results in all runtime-dependencies to be included in our final &lt;code&gt;.jar&lt;/code&gt; file.&lt;/p&gt;
  2764. &lt;/dd&gt;
  2765. &lt;dt class=&quot;hdlist1&quot;&gt;Embed-Transitive&lt;/dt&gt;
  2766. &lt;dd&gt;
  2767. &lt;p&gt;In addition to this, we will need to include all transitive packages.
  2768. Otherwise Open Liberty would not be able to find them.&lt;/p&gt;
  2769. &lt;/dd&gt;
  2770. &lt;dt class=&quot;hdlist1&quot;&gt;Export-Package&lt;/dt&gt;
  2771. &lt;dd&gt;
  2772. &lt;p&gt;You can set this (optionally), but this is also auto-generated from all packages not containing &lt;code&gt;.impl&lt;/code&gt; or &lt;code&gt;.internal&lt;/code&gt; in their package name.
  2773. In this case it is so simple, I will just keep it.&lt;/p&gt;
  2774. &lt;/dd&gt;
  2775. &lt;dt class=&quot;hdlist1&quot;&gt;Private-Package&lt;/dt&gt;
  2776. &lt;dd&gt;
  2777. &lt;p&gt;By default, everything containing &lt;code&gt;.internal&lt;/code&gt; will go here.
  2778. This means, those files are being hidden from Open Liberty.&lt;/p&gt;
  2779. &lt;/dd&gt;
  2780. &lt;dt class=&quot;hdlist1&quot;&gt;Bundle-Activator&lt;/dt&gt;
  2781. &lt;dd&gt;
  2782. &lt;p&gt;This is one of the most important option: You will need to define the point-of-entry.
  2783. Usually, the class is in the topmost package of your package structure and called either &lt;code&gt;MyModuleActivator&lt;/code&gt; or just &lt;code&gt;Activator&lt;/code&gt; (see below).&lt;/p&gt;
  2784. &lt;/dd&gt;
  2785. &lt;dt class=&quot;hdlist1&quot;&gt;Bundle-RequiredExecutionEnvironment&lt;/dt&gt;
  2786. &lt;dd&gt;
  2787. &lt;p&gt;Can be set to &lt;code&gt;JavaSE-1.8&lt;/code&gt;, but you will need Java 1.8 anyway to run Open Liberty.
  2788. But you can set it to something like &lt;code&gt;JavaSE-11&lt;/code&gt; to make this plugin incompatible with Java 8 runtimes.&lt;/p&gt;
  2789. &lt;/dd&gt;
  2790. &lt;/dl&gt;
  2791. &lt;/div&gt;
  2792. &lt;/div&gt;
  2793. &lt;/div&gt;
  2794. &lt;/div&gt;
  2795. &lt;div class=&quot;sect1&quot;&gt;
  2796. &lt;h2 id=&quot;setting_up_the_open_liberty_feature_definition&quot;&gt;Setting up the Open Liberty feature definition&lt;/h2&gt;
  2797. &lt;div class=&quot;sectionbody&quot;&gt;
  2798. &lt;div class=&quot;paragraph&quot;&gt;
  2799. &lt;p&gt;Now that we have the bundle, we need to add some code to the feature definition.
  2800. Luckily, you won&amp;#8217;t need much of configuration either.&lt;/p&gt;
  2801. &lt;/div&gt;
  2802. &lt;div class=&quot;sect2&quot;&gt;
  2803. &lt;h3 id=&quot;creating_an_esa_output_file&quot;&gt;Creating an &lt;code&gt;.esa&lt;/code&gt; output file&lt;/h3&gt;
  2804. &lt;div class=&quot;paragraph&quot;&gt;
  2805. &lt;p&gt;Change the type to &lt;code&gt;.esa&lt;/code&gt; by using &lt;code&gt;&amp;lt;type&amp;gt;esa&amp;lt;/type&amp;gt;&lt;/code&gt;.
  2806. Then, add the &lt;code&gt;esa-maven-plugin&lt;/code&gt;  and enable its extensions like so:&lt;/p&gt;
  2807. &lt;/div&gt;
  2808. &lt;div class=&quot;listingblock&quot;&gt;
  2809. &lt;div class=&quot;content&quot;&gt;
  2810. &lt;pre class=&quot;highlightjs highlight&quot;&gt;&lt;code class=&quot;language-xml hljs&quot; data-lang=&quot;xml&quot;&gt;&amp;lt;build&amp;gt;
  2811.    &amp;lt;plugins&amp;gt;
  2812.      &amp;lt;plugin&amp;gt;
  2813.        &amp;lt;groupId&amp;gt;org.apache.aries&amp;lt;/groupId&amp;gt;
  2814.        &amp;lt;artifactId&amp;gt;esa-maven-plugin&amp;lt;/artifactId&amp;gt;
  2815.        &amp;lt;extensions&amp;gt;true&amp;lt;/extensions&amp;gt;
  2816.      &amp;lt;/plugin&amp;gt;
  2817.    &amp;lt;/plugins&amp;gt;
  2818.  &amp;lt;/build&amp;gt;&lt;/code&gt;&lt;/pre&gt;
  2819. &lt;/div&gt;
  2820. &lt;/div&gt;
  2821. &lt;div class=&quot;paragraph&quot;&gt;
  2822. &lt;p&gt;This would almost run, but we need to add some more information for Open Liberty to pick it up.&lt;/p&gt;
  2823. &lt;/div&gt;
  2824. &lt;/div&gt;
  2825. &lt;div class=&quot;sect2&quot;&gt;
  2826. &lt;h3 id=&quot;prettier_version_numbers&quot;&gt;Prettier version numbers&lt;/h3&gt;
  2827. &lt;div class=&quot;paragraph&quot;&gt;
  2828. &lt;p&gt;Now you might notice, liberty feature version numbers and maven version numbers don&amp;#8217;t match and mix well.
  2829. For this reason, I decided to create a new property &lt;code&gt;project.version.libertyfeature&lt;/code&gt; which contains just the major and minor version of the maven project.&lt;/p&gt;
  2830. &lt;/div&gt;
  2831. &lt;div class=&quot;paragraph&quot;&gt;
  2832. &lt;p&gt;To achieve this, do &lt;strong&gt;not&lt;/strong&gt; define this property on your project.
  2833. If you do, the following will not work:&lt;/p&gt;
  2834. &lt;/div&gt;
  2835. &lt;div class=&quot;listingblock&quot;&gt;
  2836. &lt;div class=&quot;title&quot;&gt;Defining a feature version property in your root-pom.xml&lt;/div&gt;
  2837. &lt;div class=&quot;content&quot;&gt;
  2838. &lt;pre class=&quot;highlightjs highlight&quot;&gt;&lt;code class=&quot;language-xml hljs&quot; data-lang=&quot;xml&quot;&gt;  &amp;lt;build&amp;gt;
  2839.    &amp;lt;plugins&amp;gt;
  2840.      &amp;lt;plugin&amp;gt;
  2841.        &amp;lt;groupId&amp;gt;org.codehaus.mojo&amp;lt;/groupId&amp;gt;
  2842.        &amp;lt;artifactId&amp;gt;build-helper-maven-plugin&amp;lt;/artifactId&amp;gt;
  2843.        &amp;lt;executions&amp;gt;
  2844.          &amp;lt;execution&amp;gt;
  2845.            &amp;lt;id&amp;gt;set-liberty-version&amp;lt;/id&amp;gt;
  2846.            &amp;lt;inherited&amp;gt;true&amp;lt;/inherited&amp;gt;
  2847.            &amp;lt;goals&amp;gt;
  2848.              &amp;lt;goal&amp;gt;regex-property&amp;lt;/goal&amp;gt;
  2849.            &amp;lt;/goals&amp;gt;
  2850.            &amp;lt;configuration&amp;gt;
  2851.              &amp;lt;name&amp;gt;project.version.libertyfeature&amp;lt;/name&amp;gt;
  2852.              &amp;lt;value&amp;gt;${project.version}&amp;lt;/value&amp;gt;
  2853.              &amp;lt;regex&amp;gt;^([0-9]+)\.([0-9]+)\.([0-9]+)(-SNAPSHOT)?$&amp;lt;/regex&amp;gt;
  2854.              &amp;lt;replacement&amp;gt;$1.$2&amp;lt;/replacement&amp;gt;
  2855.              &amp;lt;failIfNoMatch&amp;gt;true&amp;lt;/failIfNoMatch&amp;gt;
  2856.            &amp;lt;/configuration&amp;gt;
  2857.          &amp;lt;/execution&amp;gt;
  2858.        &amp;lt;/executions&amp;gt;
  2859.      &amp;lt;/plugin&amp;gt;
  2860.    &amp;lt;/plugins&amp;gt;
  2861.  &amp;lt;/build&amp;gt;&lt;/code&gt;&lt;/pre&gt;
  2862. &lt;/div&gt;
  2863. &lt;/div&gt;
  2864. &lt;div class=&quot;paragraph&quot;&gt;
  2865. &lt;p&gt;Now, this will execute on every reactor module and extract the version number using regex, re-assemble it using the replacement and store the result into &lt;code&gt;project.version.libertyfeature&lt;/code&gt;.&lt;/p&gt;
  2866. &lt;/div&gt;
  2867. &lt;div class=&quot;paragraph&quot;&gt;
  2868. &lt;p&gt;I will use the property &lt;code&gt;$\{project.version.libertyfeature}&lt;/code&gt; in the next paragraph.&lt;/p&gt;
  2869. &lt;/div&gt;
  2870. &lt;/div&gt;
  2871. &lt;div class=&quot;sect2&quot;&gt;
  2872. &lt;h3 id=&quot;writing_the_esa_manifest&quot;&gt;Writing the &lt;code&gt;.esa&lt;/code&gt; manifest&lt;/h3&gt;
  2873. &lt;div class=&quot;paragraph&quot;&gt;
  2874. &lt;p&gt;Liberty needs specific information in the &lt;code&gt;.esa&lt;/code&gt; manifest file.
  2875. &lt;a href=&quot;https://www.ibm.com/docs/en/was-liberty/base?topic=manually-liberty-feature-manifest-files&quot;&gt;The full documentation is on IBMs website&lt;/a&gt;.
  2876. Let&amp;#8217;s go through this with simple words.&lt;/p&gt;
  2877. &lt;/div&gt;
  2878. &lt;div class=&quot;dlist&quot;&gt;
  2879. &lt;dl&gt;
  2880. &lt;dt class=&quot;hdlist1&quot;&gt;IBM-Feature-Version&lt;/dt&gt;
  2881. &lt;dd&gt;
  2882. &lt;p&gt;&lt;code&gt;2&lt;/code&gt;.&lt;br&gt;
  2883. Must be present and always be &lt;code&gt;2&lt;/code&gt;.&lt;/p&gt;
  2884. &lt;/dd&gt;
  2885. &lt;dt class=&quot;hdlist1&quot;&gt;Subsystem-Type&lt;/dt&gt;
  2886. &lt;dd&gt;
  2887. &lt;p&gt;Must be present and set to &lt;code&gt;osgi.subsystem.feature&lt;/code&gt;.&lt;/p&gt;
  2888. &lt;/dd&gt;
  2889. &lt;dt class=&quot;hdlist1&quot;&gt;Subsystem-SymbolicName&lt;/dt&gt;
  2890. &lt;dd&gt;
  2891. &lt;p&gt;The name of the feature and some configuration about how Liberty can use it.
  2892. The default visiblilty must be set to public, and you can define whether multiple versions of your feature can be loaded at the same time (i.e. singleton: true, default is false) or specify whether your feature is superseeded by another feature with a different name.&lt;br&gt;
  2893. Example value:&lt;br&gt;
  2894. &lt;code&gt;cowsay-$\{project.version.libertyfeature}; visibility:=public&lt;/code&gt;.&lt;/p&gt;
  2895. &lt;/dd&gt;
  2896. &lt;/dl&gt;
  2897. &lt;/div&gt;
  2898. &lt;div class=&quot;paragraph&quot;&gt;
  2899. &lt;p&gt;These are optional values:&lt;/p&gt;
  2900. &lt;/div&gt;
  2901. &lt;div class=&quot;dlist&quot;&gt;
  2902. &lt;dl&gt;
  2903. &lt;dt class=&quot;hdlist1&quot;&gt;Subsystem-Name&lt;/dt&gt;
  2904. &lt;dd&gt;
  2905. &lt;p&gt;A nice name for your feature.&lt;/p&gt;
  2906. &lt;/dd&gt;
  2907. &lt;dt class=&quot;hdlist1&quot;&gt;Subsystem-Description&lt;/dt&gt;
  2908. &lt;dd&gt;
  2909. &lt;p&gt;A longer description for your feature.&lt;/p&gt;
  2910. &lt;/dd&gt;
  2911. &lt;dt class=&quot;hdlist1&quot;&gt;Subsystem-Vendor&lt;/dt&gt;
  2912. &lt;dd&gt;
  2913. &lt;p&gt;The creator.
  2914. You can use a company name or just your name (or omit it as it is optional).&lt;/p&gt;
  2915. &lt;/dd&gt;
  2916. &lt;dt class=&quot;hdlist1&quot;&gt;Subsystem-Localization&lt;/dt&gt;
  2917. &lt;dd&gt;
  2918. &lt;p&gt;You will only need this, if you have translations for your &lt;code&gt;server.xml&lt;/code&gt; configuration or internal strings.
  2919. I recommend keeping everything in English.
  2920. It always annoys me that Liberty spits out German messages whenever I run a German app.&lt;br&gt;
  2921. &lt;strong&gt;Value:&lt;/strong&gt; set it to the resource path of your localizations within the bundle, e.g. &lt;code&gt;OSGI-INF/l10n/loc&lt;/code&gt;.&lt;/p&gt;
  2922. &lt;/dd&gt;
  2923. &lt;dt class=&quot;hdlist1&quot;&gt;IBM-ShortName&lt;/dt&gt;
  2924. &lt;dd&gt;
  2925. &lt;p&gt;What you will actually use as a feature name in your &lt;code&gt;server.xml&lt;/code&gt;.
  2926. Usually the same as the SymbolicName.
  2927. But you can change it here.&lt;/p&gt;
  2928. &lt;/dd&gt;
  2929. &lt;dt class=&quot;hdlist1&quot;&gt;IBM-AppliesTo&lt;/dt&gt;
  2930. &lt;dd&gt;
  2931. &lt;p&gt;Most commonly used for defining a minimum Liberty version like so:&lt;br&gt;
  2932. &lt;code&gt;&amp;lt;IBM-AppliesTo&amp;gt;com.ibm.websphere.appserver;productVersion=20.0.0.0+&amp;lt;/IBM-AppliesTo&amp;gt;&lt;/code&gt;&lt;/p&gt;
  2933. &lt;/dd&gt;
  2934. &lt;/dl&gt;
  2935. &lt;/div&gt;
  2936. &lt;/div&gt;
  2937. &lt;/div&gt;
  2938. &lt;/div&gt;
  2939. &lt;div class=&quot;sect1&quot;&gt;
  2940. &lt;h2 id=&quot;installing_the_feature&quot;&gt;Installing the feature&lt;/h2&gt;
  2941. &lt;div class=&quot;sectionbody&quot;&gt;
  2942. &lt;div class=&quot;sect2&quot;&gt;
  2943. &lt;h3 id=&quot;building_the_project&quot;&gt;Building the project&lt;/h3&gt;
  2944. &lt;div class=&quot;paragraph&quot;&gt;
  2945. &lt;p&gt;As always, just execute &lt;code&gt;mvn verify&lt;/code&gt;.
  2946. You will get a bundle file (&lt;code&gt;./bundle/target/cowsay-bundle-1.0.0-SNAPSHOT.jar&lt;/code&gt;), a feature definition (&lt;code&gt;./feature/target/cowsay-1.0/OSGI-INF/SUBSYSTEM.MF&lt;/code&gt;) and an esa file (&lt;code&gt;./feature/target/cowsay-1.0.esa&lt;/code&gt;).&lt;/p&gt;
  2947. &lt;/div&gt;
  2948. &lt;/div&gt;
  2949. &lt;div class=&quot;sect2&quot;&gt;
  2950. &lt;h3 id=&quot;using_featuremanager_on_ibm_websphere_liberty_profile&quot;&gt;Using &lt;code&gt;featureManager&lt;/code&gt; on IBM WebSphere Liberty Profile&lt;/h3&gt;
  2951. &lt;div class=&quot;paragraph&quot;&gt;
  2952. &lt;p&gt;The tool &lt;code&gt;featureManager&lt;/code&gt; is only available on IBM WebSphere Liberty Profile, but not on Open Liberty.
  2953. This is one of the few differences between those two.&lt;/p&gt;
  2954. &lt;/div&gt;
  2955. &lt;div class=&quot;paragraph&quot;&gt;
  2956. &lt;p&gt;To install the built esa file, use this command:&lt;/p&gt;
  2957. &lt;/div&gt;
  2958. &lt;div class=&quot;listingblock&quot;&gt;
  2959. &lt;div class=&quot;content&quot;&gt;
  2960. &lt;pre class=&quot;highlightjs highlight&quot;&gt;&lt;code class=&quot;language-bash hljs&quot; data-lang=&quot;bash&quot;&gt;# Step 0 (optional): uninstall any previouss version.
  2961. $HOME/.local/apps/wlp-22.0.0.5/bin/featureManager uninstall --verbose cowsay-1.0
  2962. # Step 1: Install the feature from a file.
  2963. $HOME/.local/apps/wlp-22.0.0.5/bin/featureManager install --verbose --to=usr $PWD/feature/target/cowsay-1.0.esa&lt;/code&gt;&lt;/pre&gt;
  2964. &lt;/div&gt;
  2965. &lt;/div&gt;
  2966. &lt;/div&gt;
  2967. &lt;div class=&quot;sect2&quot;&gt;
  2968. &lt;h3 id=&quot;using_featuremanager_on_open_liberty&quot;&gt;Using &lt;code&gt;featureManager&lt;/code&gt; on Open Liberty&lt;/h3&gt;
  2969. &lt;div class=&quot;paragraph&quot;&gt;
  2970. &lt;p&gt;While the &lt;code&gt;featureManager&lt;/code&gt; utility is not available on Open Liberty, you can use any WLP installation to install the feature to OL.
  2971. Just set the USER dir via an environment variable:&lt;/p&gt;
  2972. &lt;/div&gt;
  2973. &lt;div class=&quot;listingblock&quot;&gt;
  2974. &lt;div class=&quot;content&quot;&gt;
  2975. &lt;pre class=&quot;highlightjs highlight&quot;&gt;&lt;code class=&quot;language-bash hljs&quot; data-lang=&quot;bash&quot;&gt;export WLP_USER_DIR=&quot;$HOME/.local/apps/ol-22.0.0.5/usr&quot;
  2976. # Step 0 (optional): uninstall any previouss version.
  2977. $HOME/.local/apps/wlp-22.0.0.5/bin/featureManager uninstall --verbose cowsay-1.0
  2978. # Step 1: Install the feature from a file.
  2979. $HOME/.local/apps/wlp-22.0.0.5/bin/featureManager install --verbose --to=usr $PWD/feature/target/cowsay-1.0.esa&lt;/code&gt;&lt;/pre&gt;
  2980. &lt;/div&gt;
  2981. &lt;/div&gt;
  2982. &lt;div class=&quot;paragraph&quot;&gt;
  2983. &lt;p&gt;As I have the variable &lt;code&gt;WLP_USER_DIR&lt;/code&gt; set to &lt;code&gt;$HOME/.local/share/wlp-usr&lt;/code&gt; in my &lt;code&gt;$HOME/.profile&lt;/code&gt; file, I do not need to set any variable and will see the shared servers on any version of (Open)Liberty.&lt;/p&gt;
  2984. &lt;/div&gt;
  2985. &lt;/div&gt;
  2986. &lt;div class=&quot;sect2&quot;&gt;
  2987. &lt;h3 id=&quot;installing_the_feature_manually&quot;&gt;Installing the feature manually&lt;/h3&gt;
  2988. &lt;div class=&quot;paragraph&quot;&gt;
  2989. &lt;p&gt;If you do not want IBM WebSphere Liberty Profile to hit your harddisk for whatever reason,
  2990. you can install the feature manually.&lt;/p&gt;
  2991. &lt;/div&gt;
  2992. &lt;div class=&quot;paragraph&quot;&gt;
  2993. &lt;p&gt;Assume you are in either your $WLP/usr or $WLP_USER_DIR dir.
  2994. The resulting layout should look like this:&lt;/p&gt;
  2995. &lt;/div&gt;
  2996. &lt;div class=&quot;listingblock&quot;&gt;
  2997. &lt;div class=&quot;content&quot;&gt;
  2998. &lt;pre class=&quot;highlightjs highlight&quot;&gt;&lt;code class=&quot;language-none hljs&quot;&gt;bmarwell@wells ~/.local/share/wlp-usr $ tree extension -lFh
  2999. [   6]  extension/
  3000. └── [ 116]  lib/
  3001.    ├── [  18]  features/
  3002.    │   └── [ 545]  cowsay.mf
  3003.    └── [1.5M]  io.github.bmarwell.liberty.cowsay.bundle_1.0.0.jar
  3004.  
  3005. 2 directories, 2 files&lt;/code&gt;&lt;/pre&gt;
  3006. &lt;/div&gt;
  3007. &lt;/div&gt;
  3008. &lt;div class=&quot;olist arabic&quot;&gt;
  3009. &lt;ol class=&quot;arabic&quot;&gt;
  3010. &lt;li&gt;
  3011. &lt;p&gt;copy the bundle file &lt;code&gt;./bundle/target/cowsay-bundle-1.0.0-SNAPSHOT.jar&lt;/code&gt; to &lt;code&gt;$WLP_USER_DIR/extensions/lib/${groupid}.bundle_${version}.jar&lt;/code&gt;.&lt;/p&gt;
  3012. &lt;/li&gt;
  3013. &lt;li&gt;
  3014. &lt;p&gt;copy the feature descriptor &lt;code&gt;./feature/target/cowsay-1.0/OSGI-INF/SUBSYSTEM.MF&lt;/code&gt; to &lt;code&gt;$WLP_USER_DIR/extensions/lib/features/${featurename}.mf&lt;/code&gt;.&lt;/p&gt;
  3015. &lt;/li&gt;
  3016. &lt;/ol&gt;
  3017. &lt;/div&gt;
  3018. &lt;div class=&quot;literalblock&quot;&gt;
  3019. &lt;div class=&quot;content&quot;&gt;
  3020. &lt;pre&gt;     ___________________________________
  3021.    &amp;lt; That&apos;s it! Thank you for reading! &amp;gt;
  3022.     -----------------------------------
  3023.            \   ^__^
  3024.             \  (oo)\_______
  3025.                (__)\       )\/\
  3026.                    ||----w |
  3027.                    ||     ||
  3028.  &lt;/pre&gt;
  3029. &lt;/div&gt;
  3030. &lt;/div&gt;
  3031. &lt;/div&gt;
  3032. &lt;/div&gt;
  3033. &lt;/div&gt;
  3034. &lt;div class=&quot;sect1&quot;&gt;
  3035. &lt;h2 id=&quot;where_to_go_from_here&quot;&gt;Where to go from here&lt;/h2&gt;
  3036. &lt;div class=&quot;sectionbody&quot;&gt;
  3037. &lt;div class=&quot;paragraph&quot;&gt;
  3038. &lt;p&gt;This article only covered the basics.
  3039. There are many things on my mind which need to be explained in further blog posts.&lt;/p&gt;
  3040. &lt;/div&gt;
  3041. &lt;div class=&quot;paragraph&quot;&gt;
  3042. &lt;p&gt;Be sure to follow &lt;a href=&quot;/tags/OpenLiberty.html&quot;&gt;my Open Liberty tag&lt;/a&gt; on this blog!&lt;/p&gt;
  3043. &lt;/div&gt;
  3044. &lt;div class=&quot;dlist&quot;&gt;
  3045. &lt;dl&gt;
  3046. &lt;dt class=&quot;hdlist1&quot;&gt;Using and relying on existing features&lt;/dt&gt;
  3047. &lt;dd&gt;
  3048. &lt;p&gt;You can use existing features, like JNDI for browsing registered datasources or servlet and JSPs for creating simple endpoints.
  3049. It gets even more complicated with version ranges, so I will dedicate another article to this topic.&lt;/p&gt;
  3050. &lt;/dd&gt;
  3051. &lt;dt class=&quot;hdlist1&quot;&gt;Adding integration tests&lt;/dt&gt;
  3052. &lt;dd&gt;
  3053. &lt;p&gt;While you can probably easily add unit tests to cover your code logic,
  3054. integration tests are a different thing.
  3055. You&amp;#8217;d want to see if your plugin actually can be installed and started on Liberty, right?&lt;/p&gt;
  3056. &lt;/dd&gt;
  3057. &lt;/dl&gt;
  3058. &lt;/div&gt;
  3059. &lt;div class=&quot;paragraph&quot;&gt;
  3060. &lt;p&gt;As of writing, the &lt;code&gt;liberty-maven-plugin&lt;/code&gt; sadly does not support maven property resolution nor maven reactor feature resolution yet.
  3061. I have opened an issue on GitHub for the &lt;a href=&quot;https://github.com/OpenLiberty/ci.maven/issues/1529&quot;&gt;reactor esa module&lt;/a&gt;
  3062. as well as &lt;a href=&quot;https://github.com/OpenLiberty/ci.maven/issues/1530&quot;&gt;for the maven property resolution&lt;/a&gt;.&lt;/p&gt;
  3063. &lt;/div&gt;
  3064. &lt;div class=&quot;paragraph&quot;&gt;
  3065. &lt;p&gt;As a workaround, manually copying works.
  3066. You can see this in action in the actual code repo: &lt;a href=&quot;https://github.com/bmarwell/cowsay-liberty-feature&quot; class=&quot;bare&quot;&gt;https://github.com/bmarwell/cowsay-liberty-feature&lt;/a&gt;.&lt;/p&gt;
  3067. &lt;/div&gt;
  3068. &lt;div class=&quot;dlist&quot;&gt;
  3069. &lt;dl&gt;
  3070. &lt;dt class=&quot;hdlist1&quot;&gt;Manually writing &lt;code&gt;.esa&lt;/code&gt; and &lt;code&gt;bundle&lt;/code&gt; manifest files&lt;/dt&gt;
  3071. &lt;dd&gt;
  3072. &lt;p&gt;This is what I had to do on my other non-public project.
  3073. Some statements, like &lt;code&gt;Subsystem-Content&lt;/code&gt; are auto-generated and cannot be overriden.
  3074. The only way around this is to enable resource-filtering and configure the plugins to use the filtered manifest file instead.&lt;/p&gt;
  3075. &lt;/dd&gt;
  3076. &lt;dt class=&quot;hdlist1&quot;&gt;Extending the idea of this feature&lt;/dt&gt;
  3077. &lt;dd&gt;
  3078. &lt;p&gt;Yes, of course I created a &quot;real&quot; repository!
  3079. Head over to &lt;a href=&quot;https://github.com/bmarwell/cowsay-liberty-feature&quot; class=&quot;bare&quot;&gt;https://github.com/bmarwell/cowsay-liberty-feature&lt;/a&gt;. :-)&lt;/p&gt;
  3080. &lt;/dd&gt;
  3081. &lt;/dl&gt;
  3082. &lt;/div&gt;
  3083. &lt;div class=&quot;paragraph&quot;&gt;
  3084. &lt;p&gt;… and many more ideas.&lt;/p&gt;
  3085. &lt;/div&gt;
  3086. &lt;/div&gt;
  3087. &lt;/div&gt;
  3088.    </content>
  3089.  </entry>
  3090.  
  3091.  <entry>
  3092.    <!-- lang="en-GB"  -->
  3093.    <title>Using JJWT with the Jakarta JSON Binding API</title>
  3094.    <link href="https://blog.bmarwell.de/2022/05/12/using-jjwt-with-jakarta-jsonb.html"/>
  3095.    <id>https://blog.bmarwell.de/2022/05/12/using-jjwt-with-jakarta-jsonb.html</id>
  3096.    <published>2022-05-12T20:07:35Z</published>
  3097.    <updated>2022-05-12T20:07:35Z</updated>
  3098.    <author>
  3099.      <name>Benjamin Marwell</name>
  3100.    </author>
  3101.    <content type="html">
  3102.      &lt;div id=&quot;preamble&quot;&gt;
  3103. &lt;div class=&quot;sectionbody&quot;&gt;
  3104. &lt;div class=&quot;paragraph&quot;&gt;
  3105. &lt;p&gt;As you may have seen in my earlier posts, &lt;a href=&quot;https://github.com/jwtk/jjwt&quot;&gt;JJWT&lt;/a&gt; is a sensible choice for a JSON Web Token (JWT, pronounced &apos;jot&apos;) Library.
  3106. JJWT is separated into a few modules: The API, the implementation and the JSON serializer.
  3107. You can currently choose between Jackson and GSON as a JSON serializer.
  3108. But if you work in a Jakarta EE or MicroProfile environment, you might want to consider your own &lt;a href=&quot;https://projects.eclipse.org/projects/ee4j.jsonb&quot;&gt;JSON-B&lt;/a&gt; provider instead.&lt;/p&gt;
  3109. &lt;/div&gt;
  3110. &lt;/div&gt;
  3111. &lt;/div&gt;
  3112. &lt;div class=&quot;sect1&quot;&gt;
  3113. &lt;h2 id=&quot;what_is_jjwt&quot;&gt;What is JJWT?&lt;/h2&gt;
  3114. &lt;div class=&quot;sectionbody&quot;&gt;
  3115. &lt;div class=&quot;paragraph&quot;&gt;
  3116. &lt;p&gt;JJWT (&lt;a href=&quot;https://github.com/jwtk/jjwt/pull/727&quot;&gt;pronounced: jay-jay-doubleyou-tee, not jay-jot&lt;/a&gt;) is a library which is able to both create and parse JWTs in Java.
  3117. It is compatible with Java 7 (because of Android 6 Marshmellow which needs to be supported) and lightweight.
  3118. JJWT is used in many Open Source or corporate projects.
  3119. While there is also the &lt;a href=&quot;https://github.com/auth0/java-jwt&quot;&gt;auth0/java-jwt&lt;/a&gt; library, it is not uncommon to see JJWT being used instead.&lt;/p&gt;
  3120. &lt;/div&gt;
  3121. &lt;/div&gt;
  3122. &lt;/div&gt;
  3123. &lt;div class=&quot;sect1&quot;&gt;
  3124. &lt;h2 id=&quot;why_would_i_want_to_use_my_own_json_provider&quot;&gt;Why would I want to use my own JSON provider?&lt;/h2&gt;
  3125. &lt;div class=&quot;sectionbody&quot;&gt;
  3126. &lt;div class=&quot;paragraph&quot;&gt;
  3127. &lt;p&gt;You will want to use your own JSON provider with JJWT, if:&lt;/p&gt;
  3128. &lt;/div&gt;
  3129. &lt;div class=&quot;ulist&quot;&gt;
  3130. &lt;ul&gt;
  3131. &lt;li&gt;
  3132. &lt;p&gt;… you are in a Jakarta EE or Microprofile Environment already&lt;/p&gt;
  3133. &lt;/li&gt;
  3134. &lt;li&gt;
  3135. &lt;p&gt;… don’t want to pull in a specific JSON implementation&lt;/p&gt;
  3136. &lt;/li&gt;
  3137. &lt;li&gt;
  3138. &lt;p&gt;… you are not using either Jackson, org.json or GSON&lt;/p&gt;
  3139. &lt;/li&gt;
  3140. &lt;/ul&gt;
  3141. &lt;/div&gt;
  3142. &lt;div class=&quot;paragraph&quot;&gt;
  3143. &lt;p&gt;In this case, using an implementation-agnostic JSON-B provider allows you to switch between implementations at runtime.
  3144. In other words, you do not need to reimplement the JSON serializer for running on another Application Server or when switching out libraries.&lt;/p&gt;
  3145. &lt;/div&gt;
  3146. &lt;/div&gt;
  3147. &lt;/div&gt;
  3148. &lt;div class=&quot;sect1&quot;&gt;
  3149. &lt;h2 id=&quot;implementing_the_json_provider&quot;&gt;Implementing the JSON provider&lt;/h2&gt;
  3150. &lt;div class=&quot;sectionbody&quot;&gt;
  3151. &lt;div class=&quot;paragraph&quot;&gt;
  3152. &lt;p&gt;You only need to implement two classes and add the service files.&lt;/p&gt;
  3153. &lt;/div&gt;
  3154. &lt;div class=&quot;paragraph&quot;&gt;
  3155. &lt;p&gt;These are the implementations which will not pull in a specific provider:&lt;/p&gt;
  3156. &lt;/div&gt;
  3157. &lt;div class=&quot;listingblock&quot;&gt;
  3158. &lt;div class=&quot;title&quot;&gt;&lt;code&gt;io.jsonwebtoken.jsonb.io.JsonbDeserializer.java&lt;/code&gt;&lt;/div&gt;
  3159. &lt;div class=&quot;content&quot;&gt;
  3160. &lt;pre class=&quot;highlightjs highlight&quot;&gt;&lt;code class=&quot;language-java hljs&quot; data-lang=&quot;java&quot;&gt;/*
  3161. * Copyright (C) 2014 jsonwebtoken.io
  3162. *
  3163. * Licensed under the Apache License, Version 2.0 (the &quot;License&quot;);
  3164. * you may not use this file except in compliance with the License.
  3165. * You may obtain a copy of the License at
  3166. *
  3167. *     http://www.apache.org/licenses/LICENSE-2.0
  3168. *
  3169. * Unless required by applicable law or agreed to in writing, software
  3170. * distributed under the License is distributed on an &quot;AS IS&quot; BASIS,
  3171. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  3172. * See the License for the specific language governing permissions and
  3173. * limitations under the License.
  3174. */
  3175. package io.jsonwebtoken.jsonb.io;
  3176.  
  3177. import io.jsonwebtoken.io.DeserializationException;
  3178. import io.jsonwebtoken.io.Deserializer;
  3179.  
  3180. import javax.json.bind.Jsonb;
  3181. import javax.json.bind.JsonbException;
  3182. import java.nio.charset.StandardCharsets;
  3183.  
  3184. import static java.util.Objects.requireNonNull;
  3185.  
  3186. /**
  3187. * @since JJWT_RELEASE_VERSION
  3188. */
  3189. public class JsonbDeserializer&amp;lt;T&amp;gt; implements Deserializer&amp;lt;T&amp;gt; {
  3190.  
  3191.    private final Class&amp;lt;T&amp;gt; returnType;
  3192.    private final Jsonb jsonb;
  3193.  
  3194.    @SuppressWarnings(&quot;unused&quot;) //used via reflection by RuntimeClasspathDeserializerLocator
  3195.    public JsonbDeserializer() {
  3196.        this(JsonbSerializer.DEFAULT_JSONB);
  3197.    }
  3198.  
  3199.    @SuppressWarnings({&quot;unchecked&quot;, &quot;WeakerAccess&quot;, &quot;unused&quot;}) // for end-users providing a custom ObjectMapper
  3200.    public JsonbDeserializer(Jsonb jsonb) {
  3201.        this(jsonb, (Class&amp;lt;T&amp;gt;) Object.class);
  3202.    }
  3203.  
  3204.    private JsonbDeserializer(Jsonb jsonb, Class&amp;lt;T&amp;gt; returnType) {
  3205.        requireNonNull(jsonb, &quot;ObjectMapper cannot be null.&quot;);
  3206.        requireNonNull(returnType, &quot;Return type cannot be null.&quot;);
  3207.        this.jsonb = jsonb;
  3208.        this.returnType = returnType;
  3209.    }
  3210.  
  3211.    @Override
  3212.    public T deserialize(byte[] bytes) throws DeserializationException {
  3213.        try {
  3214.            return readValue(bytes);
  3215.        } catch (JsonbException jsonbException) {
  3216.            String msg = &quot;Unable to deserialize bytes into a &quot; + returnType.getName() + &quot; instance: &quot; + jsonbException.getMessage();
  3217.            throw new DeserializationException(msg, jsonbException);
  3218.        }
  3219.    }
  3220.  
  3221.    protected T readValue(byte[] bytes) {
  3222.        return jsonb.fromJson(new String(bytes, StandardCharsets.UTF_8), returnType);
  3223.    }
  3224.  
  3225. }&lt;/code&gt;&lt;/pre&gt;
  3226. &lt;/div&gt;
  3227. &lt;/div&gt;
  3228. &lt;div class=&quot;listingblock&quot;&gt;
  3229. &lt;div class=&quot;title&quot;&gt;&lt;code&gt;io.jsonwebtoken.jsonb.io.JsonbSserializer.java&lt;/code&gt;&lt;/div&gt;
  3230. &lt;div class=&quot;content&quot;&gt;
  3231. &lt;pre class=&quot;highlightjs highlight&quot;&gt;&lt;code class=&quot;language-java hljs&quot; data-lang=&quot;java&quot;&gt;/*
  3232. * Copyright (C) 2014 jsonwebtoken.io
  3233. *
  3234. * Licensed under the Apache License, Version 2.0 (the &quot;License&quot;);
  3235. * you may not use this file except in compliance with the License.
  3236. * You may obtain a copy of the License at
  3237. *
  3238. *     http://www.apache.org/licenses/LICENSE-2.0
  3239. *
  3240. * Unless required by applicable law or agreed to in writing, software
  3241. * distributed under the License is distributed on an &quot;AS IS&quot; BASIS,
  3242. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  3243. * See the License for the specific language governing permissions and
  3244. * limitations under the License.
  3245. */
  3246. package io.jsonwebtoken.jsonb.io;
  3247.  
  3248. import io.jsonwebtoken.io.Encoders;
  3249. import io.jsonwebtoken.io.SerializationException;
  3250. import io.jsonwebtoken.io.Serializer;
  3251. import io.jsonwebtoken.lang.Assert;
  3252.  
  3253. import javax.json.bind.Jsonb;
  3254. import javax.json.bind.JsonbBuilder;
  3255. import javax.json.bind.JsonbException;
  3256. import java.nio.charset.StandardCharsets;
  3257.  
  3258. import static java.util.Objects.requireNonNull;
  3259.  
  3260. /**
  3261. * @since JJWT_RELEASE_VERSION
  3262. */
  3263. public class JsonbSerializer&amp;lt;T&amp;gt; implements Serializer&amp;lt;T&amp;gt; {
  3264.  
  3265.    static final Jsonb DEFAULT_JSONB = JsonbBuilder.create();
  3266.  
  3267.    private final Jsonb jsonb;
  3268.  
  3269.    @SuppressWarnings(&quot;unused&quot;) //used via reflection by RuntimeClasspathDeserializerLocator
  3270.    public JsonbSerializer() {
  3271.        this(DEFAULT_JSONB);
  3272.    }
  3273.  
  3274.    @SuppressWarnings(&quot;WeakerAccess&quot;) //intended for end-users to use when providing a custom ObjectMapper
  3275.    public JsonbSerializer(Jsonb jsonb) {
  3276.        requireNonNull(jsonb, &quot;Jsonb cannot be null.&quot;);
  3277.        this.jsonb = jsonb;
  3278.    }
  3279.  
  3280.    @Override
  3281.    public byte[] serialize(T t) throws SerializationException {
  3282.        requireNonNull(t, &quot;Object to serialize cannot be null.&quot;);
  3283.        try {
  3284.            return writeValueAsBytes(t);
  3285.        } catch (JsonbException jsonbException) {
  3286.            String msg = &quot;Unable to serialize object: &quot; + jsonbException.getMessage();
  3287.            throw new SerializationException(msg, jsonbException);
  3288.        }
  3289.    }
  3290.  
  3291.    @SuppressWarnings(&quot;WeakerAccess&quot;) //for testing
  3292.    protected byte[] writeValueAsBytes(T t) {
  3293.        final Object obj;
  3294.  
  3295.        if (t instanceof byte[]) {
  3296.            obj = Encoders.BASE64.encode((byte[]) t);
  3297.        } else if (t instanceof char[]) {
  3298.            obj = new String((char[]) t);
  3299.        } else {
  3300.            obj = t;
  3301.        }
  3302.  
  3303.        return this.jsonb.toJson(obj).getBytes(StandardCharsets.UTF_8);
  3304.    }
  3305. }&lt;/code&gt;&lt;/pre&gt;
  3306. &lt;/div&gt;
  3307. &lt;/div&gt;
  3308. &lt;/div&gt;
  3309. &lt;/div&gt;
  3310. &lt;div class=&quot;sect1&quot;&gt;
  3311. &lt;h2 id=&quot;pr_on_github&quot;&gt;PR on GitHub&lt;/h2&gt;
  3312. &lt;div class=&quot;sectionbody&quot;&gt;
  3313. &lt;div class=&quot;paragraph&quot;&gt;
  3314. &lt;p&gt;I am posting the code here, because &lt;a href=&quot;https://github.com/jwtk/jjwt/pull/720&quot;&gt;my PR #720&lt;/a&gt; still has not been merged.
  3315. This will only get merged once Java 8 is the baseline, although the PR would work with the current Java 7 main branch.
  3316. Only this single module would have been a Java 8 module, but Les (the maintainer) decided against it as the build would get slightly more complicated and modules requiring different versions of Java are confusing to users.&lt;/p&gt;
  3317. &lt;/div&gt;
  3318. &lt;/div&gt;
  3319. &lt;/div&gt;
  3320. &lt;div class=&quot;sect1&quot;&gt;
  3321. &lt;h2 id=&quot;alternatives&quot;&gt;Alternatives&lt;/h2&gt;
  3322. &lt;div class=&quot;sectionbody&quot;&gt;
  3323. &lt;div class=&quot;paragraph&quot;&gt;
  3324. &lt;p&gt;Instead of using the more abstract JSON-B provider, you could add every implementation:&lt;/p&gt;
  3325. &lt;/div&gt;
  3326. &lt;div class=&quot;ulist&quot;&gt;
  3327. &lt;ul&gt;
  3328. &lt;li&gt;
  3329. &lt;p&gt;&lt;a href=&quot;https://github.com/eclipse-ee4j/yasson&quot;&gt;Eclipse Yasson&lt;/a&gt;-Provider&lt;/p&gt;
  3330. &lt;/li&gt;
  3331. &lt;li&gt;
  3332. &lt;p&gt;&lt;a href=&quot;https://johnzon.apache.org/&quot;&gt;Apache Johnzon&lt;/a&gt;-Provider&lt;/p&gt;
  3333. &lt;/li&gt;
  3334. &lt;li&gt;
  3335. &lt;p&gt;Possibly others&lt;/p&gt;
  3336. &lt;/li&gt;
  3337. &lt;/ul&gt;
  3338. &lt;/div&gt;
  3339. &lt;div class=&quot;paragraph&quot;&gt;
  3340. &lt;p&gt;Genson however does not implement JSON-B APIs, so you would need to write a module for this anyway.&lt;/p&gt;
  3341. &lt;/div&gt;
  3342. &lt;/div&gt;
  3343. &lt;/div&gt;
  3344.    </content>
  3345.  </entry>
  3346.  
  3347.  <entry>
  3348.    <!-- lang="en-GB"  -->
  3349.    <title>Apache Shiro: JWT Realm with JJWT</title>
  3350.    <link href="https://blog.bmarwell.de/2022/04/26/apache-shiro-jwt-authentication-jjwt.html"/>
  3351.    <id>https://blog.bmarwell.de/2022/04/26/apache-shiro-jwt-authentication-jjwt.html</id>
  3352.    <published>2022-04-26T21:18:00Z</published>
  3353.    <updated>2022-04-26T21:18:00Z</updated>
  3354.    <author>
  3355.      <name>Benjamin Marwell</name>
  3356.    </author>
  3357.    <content type="html">
  3358.      &lt;div id=&quot;preamble&quot;&gt;
  3359. &lt;div class=&quot;sectionbody&quot;&gt;
  3360. &lt;div class=&quot;paragraph&quot;&gt;
  3361. &lt;p&gt;In this tutorial you will learn how to secure your JAX-RS endpoints using &lt;a href=&quot;https://shiro.apache.org&quot;&gt;Apache Shiro&lt;/a&gt; and JSON Web Tokens (JWT).&lt;/p&gt;
  3362. &lt;/div&gt;
  3363. &lt;div class=&quot;paragraph&quot;&gt;
  3364. &lt;p&gt;Prerequisites:&lt;/p&gt;
  3365. &lt;/div&gt;
  3366. &lt;div class=&quot;ulist&quot;&gt;
  3367. &lt;ul&gt;
  3368. &lt;li&gt;
  3369. &lt;p&gt;Make sure you have read and understand my previous article, &lt;a href=&quot;/2022/04/07/jax-rs-endpoints-apache-shiro.html&quot;&gt;Securing JAX-RS endpoints using Apache Shiro&lt;/a&gt;.&lt;/p&gt;
  3370. &lt;/li&gt;
  3371. &lt;li&gt;
  3372. &lt;p&gt;Java 17.
  3373. While this tutorial will only make use of Jakarta EE 7 and Eclipse MicroProfile 2.0 features and would run on Java 8, I use Java 17 to keep the code a bit shorter.&lt;/p&gt;
  3374. &lt;/li&gt;
  3375. &lt;li&gt;
  3376. &lt;p&gt;A JakartaEE compliant application server.
  3377. Throughout this tutorial, &lt;a href=&quot;https://openliberty.io&quot;&gt;IBM OpenLiberty&lt;/a&gt; will be used.
  3378. I find it an excellent and easy-to-use Java/Jakarta/MicroProfile application server.&lt;/p&gt;
  3379. &lt;/li&gt;
  3380. &lt;/ul&gt;
  3381. &lt;/div&gt;
  3382. &lt;div id=&quot;toc&quot; class=&quot;toc&quot;&gt;
  3383. &lt;div id=&quot;toctitle&quot; class=&quot;title&quot;&gt;Table of Contents&lt;/div&gt;
  3384. &lt;ul class=&quot;sectlevel1&quot;&gt;
  3385. &lt;li&gt;&lt;a href=&quot;#goals_of_this_tutorial&quot;&gt;Goals of this Tutorial&lt;/a&gt;
  3386. &lt;ul class=&quot;sectlevel2&quot;&gt;
  3387. &lt;li&gt;&lt;a href=&quot;#non_goals_for_this_tutorial&quot;&gt;Non-Goals for this tutorial&lt;/a&gt;&lt;/li&gt;
  3388. &lt;/ul&gt;
  3389. &lt;/li&gt;
  3390. &lt;li&gt;&lt;a href=&quot;#setting_up_the_project&quot;&gt;Setting up the project&lt;/a&gt;
  3391. &lt;ul class=&quot;sectlevel2&quot;&gt;
  3392. &lt;li&gt;&lt;a href=&quot;#keystore_module&quot;&gt;»keystore« module&lt;/a&gt;&lt;/li&gt;
  3393. &lt;li&gt;&lt;a href=&quot;#start_server&quot;&gt;»start« server&lt;/a&gt;&lt;/li&gt;
  3394. &lt;li&gt;&lt;a href=&quot;#issuer_server&quot;&gt;»issuer« server&lt;/a&gt;&lt;/li&gt;
  3395. &lt;li&gt;&lt;a href=&quot;#finish_server&quot;&gt;»finish« server&lt;/a&gt;&lt;/li&gt;
  3396. &lt;li&gt;&lt;a href=&quot;#inspecting_the_start_server&quot;&gt;Inspecting the start server&lt;/a&gt;&lt;/li&gt;
  3397. &lt;/ul&gt;
  3398. &lt;/li&gt;
  3399. &lt;li&gt;&lt;a href=&quot;#digression_shiro_terms_and_features&quot;&gt;Digression: Shiro Terms and Features&lt;/a&gt;
  3400. &lt;ul class=&quot;sectlevel2&quot;&gt;
  3401. &lt;li&gt;&lt;a href=&quot;#shiro_httpauthenticationfilter&quot;&gt;Shiro HttpAuthenticationFilter&lt;/a&gt;&lt;/li&gt;
  3402. &lt;li&gt;&lt;a href=&quot;#shiro_credentials&quot;&gt;Shiro Credentials&lt;/a&gt;&lt;/li&gt;
  3403. &lt;li&gt;&lt;a href=&quot;#shiro_token&quot;&gt;Shiro Token&lt;/a&gt;&lt;/li&gt;
  3404. &lt;li&gt;&lt;a href=&quot;#shiro_realm&quot;&gt;Shiro Realm&lt;/a&gt;&lt;/li&gt;
  3405. &lt;li&gt;&lt;a href=&quot;#shiro_credentialsmatcher&quot;&gt;Shiro CredentialsMatcher&lt;/a&gt;&lt;/li&gt;
  3406. &lt;li&gt;&lt;a href=&quot;#shiro_rolepermissionresolver&quot;&gt;Shiro RolePermissionResolver&lt;/a&gt;&lt;/li&gt;
  3407. &lt;/ul&gt;
  3408. &lt;/li&gt;
  3409. &lt;li&gt;&lt;a href=&quot;#implementing_jwts_in_shiro&quot;&gt;Implementing JWTs in Shiro&lt;/a&gt;
  3410. &lt;ul class=&quot;sectlevel2&quot;&gt;
  3411. &lt;li&gt;&lt;a href=&quot;#implementing_the_jwtparser&quot;&gt;Implementing the JwtParser&lt;/a&gt;&lt;/li&gt;
  3412. &lt;li&gt;&lt;a href=&quot;#credentials_filter_jwthttpauthenticator&quot;&gt;Credentials Filter: JwtHttpAuthenticator&lt;/a&gt;&lt;/li&gt;
  3413. &lt;li&gt;&lt;a href=&quot;#implementing_the_jwtrealm&quot;&gt;Implementing the JwtRealm&lt;/a&gt;
  3414. &lt;ul class=&quot;sectlevel3&quot;&gt;
  3415. &lt;li&gt;&lt;a href=&quot;#overriding_getname&quot;&gt;Overriding &lt;code&gt;getName()&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
  3416. &lt;li&gt;&lt;a href=&quot;#overriding_getauthenticationtokenclass&quot;&gt;Overriding &lt;code&gt;getAuthenticationTokenClass()&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
  3417. &lt;li&gt;&lt;a href=&quot;#overriding_dogetauthenticationinfoauthenticationtoken_token&quot;&gt;Overriding &lt;code&gt;doGetAuthenticationInfo(AuthenticationToken token)&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
  3418. &lt;li&gt;&lt;a href=&quot;#overriding_dogetauthorizationinfoprincipalcollection_principals&quot;&gt;Overriding &lt;code&gt;doGetAuthorizationInfo(PrincipalCollection principals)&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
  3419. &lt;li&gt;&lt;a href=&quot;#activating_jwtrealm&quot;&gt;Activating JwtRealm&lt;/a&gt;&lt;/li&gt;
  3420. &lt;/ul&gt;
  3421. &lt;/li&gt;
  3422. &lt;li&gt;&lt;a href=&quot;#credentialsmatcher_for_jwts&quot;&gt;CredentialsMatcher for JWTs&lt;/a&gt;
  3423. &lt;ul class=&quot;sectlevel3&quot;&gt;
  3424. &lt;li&gt;&lt;a href=&quot;#disabling_the_credentialsmatcher_not_recommended&quot;&gt;Disabling the CredentialsMatcher (not recommended)&lt;/a&gt;&lt;/li&gt;
  3425. &lt;li&gt;&lt;a href=&quot;#implementing_a_jwtcredentialsmatcher&quot;&gt;Implementing a JwtCredentialsMatcher&lt;/a&gt;&lt;/li&gt;
  3426. &lt;/ul&gt;
  3427. &lt;/li&gt;
  3428. &lt;/ul&gt;
  3429. &lt;/li&gt;
  3430. &lt;li&gt;&lt;a href=&quot;#conclusion&quot;&gt;Conclusion&lt;/a&gt;&lt;/li&gt;
  3431. &lt;li&gt;&lt;a href=&quot;#further_reading&quot;&gt;Further reading&lt;/a&gt;&lt;/li&gt;
  3432. &lt;/ul&gt;
  3433. &lt;/div&gt;
  3434. &lt;/div&gt;
  3435. &lt;/div&gt;
  3436. &lt;div class=&quot;sect1&quot;&gt;
  3437. &lt;h2 id=&quot;goals_of_this_tutorial&quot;&gt;Goals of this Tutorial&lt;/h2&gt;
  3438. &lt;div class=&quot;sectionbody&quot;&gt;
  3439. &lt;div class=&quot;paragraph&quot;&gt;
  3440. &lt;p&gt;By the end of this tutorial, you will have learned how to set up Apache Shiro and integrate JWTs (JSON Web Tokens) using &lt;a href=&quot;https://github.com/jwtk/jjwt&quot;&gt;JJWT&lt;/a&gt;.
  3441. There are a couple of reasons why those two libraries have been chosen.&lt;/p&gt;
  3442. &lt;/div&gt;
  3443. &lt;div class=&quot;ulist&quot;&gt;
  3444. &lt;ul&gt;
  3445. &lt;li&gt;
  3446. &lt;p&gt;Shiro excels at resolving roles into fine-granular permissions.
  3447. Few other frameworks can actually do this.&lt;/p&gt;
  3448. &lt;/li&gt;
  3449. &lt;li&gt;
  3450. &lt;p&gt;Shiro brings annotations which are (in some sense) more powerful than other annotations:&lt;/p&gt;
  3451. &lt;div class=&quot;ulist&quot;&gt;
  3452. &lt;ul&gt;
  3453. &lt;li&gt;
  3454. &lt;p&gt;Jakarta EE’s Security API does not have annotations for JAX-RS.&lt;/p&gt;
  3455. &lt;/li&gt;
  3456. &lt;li&gt;
  3457. &lt;p&gt;But on the other hand Shiro lacks expressions in JAX-RS annotations.&lt;/p&gt;
  3458. &lt;/li&gt;
  3459. &lt;li&gt;
  3460. &lt;p&gt;… just to name two random but very obvious differences.&lt;/p&gt;
  3461. &lt;/li&gt;
  3462. &lt;/ul&gt;
  3463. &lt;/div&gt;
  3464. &lt;/li&gt;
  3465. &lt;li&gt;
  3466. &lt;p&gt;JSON Web Tokens transport signed (and therefore trusted) authentication AND authorization information.
  3467. Even if intercepted, attackers cannot make much use of it for a few reasons:&lt;/p&gt;
  3468. &lt;div class=&quot;ulist&quot;&gt;
  3469. &lt;ul&gt;
  3470. &lt;li&gt;
  3471. &lt;p&gt;JWTs have an expiry date.
  3472. Even if you can extend them, you can usually only do so with a second extension token, and only a few times before they expire for good.&lt;/p&gt;
  3473. &lt;/li&gt;
  3474. &lt;li&gt;
  3475. &lt;p&gt;There can be multiple JWTs for your (web) application, based on what functionality you are using at the moment.
  3476. Even if an attacker intercepts your JWT, they are usually only able to do a very confined range of things with it.&lt;/p&gt;
  3477. &lt;/li&gt;
  3478. &lt;/ul&gt;
  3479. &lt;/div&gt;
  3480. &lt;/li&gt;
  3481. &lt;/ul&gt;
  3482. &lt;/div&gt;
  3483. &lt;div class=&quot;paragraph&quot;&gt;
  3484. &lt;p&gt;For a showcase, we are setting up a mock JWT issuing server.&lt;/p&gt;
  3485. &lt;/div&gt;
  3486. &lt;div class=&quot;sect2&quot;&gt;
  3487. &lt;h3 id=&quot;non_goals_for_this_tutorial&quot;&gt;Non-Goals for this tutorial&lt;/h3&gt;
  3488. &lt;div class=&quot;ulist&quot;&gt;
  3489. &lt;ul&gt;
  3490. &lt;li&gt;
  3491. &lt;p&gt;Explain JWTs and how they are created and used, extended etc.&lt;/p&gt;
  3492. &lt;/li&gt;
  3493. &lt;li&gt;
  3494. &lt;p&gt;&lt;strong&gt;All&lt;/strong&gt; the best practices.
  3495. I will mention where I deviate from best practices, but will not be able to show a state-of-the-art implementation for reasons of brevity.&lt;/p&gt;
  3496. &lt;/li&gt;
  3497. &lt;/ul&gt;
  3498. &lt;/div&gt;
  3499. &lt;/div&gt;
  3500. &lt;/div&gt;
  3501. &lt;/div&gt;
  3502. &lt;div class=&quot;sect1&quot;&gt;
  3503. &lt;h2 id=&quot;setting_up_the_project&quot;&gt;Setting up the project&lt;/h2&gt;
  3504. &lt;div class=&quot;sectionbody&quot;&gt;
  3505. &lt;div class=&quot;paragraph&quot;&gt;
  3506. &lt;p&gt;All the code is in my GitHub repository, &lt;a href=&quot;https://github.com/bmarwell/shiro-jwt-showcase&quot;&gt;bmarwell/shiro-jwt-showcase&lt;/a&gt;.
  3507. A short description of the repository will follow.&lt;/p&gt;
  3508. &lt;/div&gt;
  3509. &lt;div class=&quot;sect2&quot;&gt;
  3510. &lt;h3 id=&quot;keystore_module&quot;&gt;»keystore« module&lt;/h3&gt;
  3511. &lt;div class=&quot;paragraph&quot;&gt;
  3512. &lt;p&gt;The »&lt;strong&gt;keystore&lt;/strong&gt;« maven module contains maven code to set up a sample keystore (containing the private key for the issuing server) and a truststore where only the public key is present.&lt;/p&gt;
  3513. &lt;/div&gt;
  3514. &lt;/div&gt;
  3515. &lt;div class=&quot;sect2&quot;&gt;
  3516. &lt;h3 id=&quot;start_server&quot;&gt;»start« server&lt;/h3&gt;
  3517. &lt;div class=&quot;paragraph&quot;&gt;
  3518. &lt;p&gt;The »&lt;strong&gt;start&lt;/strong&gt;« directory contains a sample setup.
  3519. You can run &lt;code&gt;./mvnw liberty:dev&lt;/code&gt; to start a development server.
  3520. It is basically the same server as we left it in the previous tutorial.
  3521. It does not make any use of either the keystore dependency nor the JJWT library.&lt;/p&gt;
  3522. &lt;/div&gt;
  3523. &lt;/div&gt;
  3524. &lt;div class=&quot;sect2&quot;&gt;
  3525. &lt;h3 id=&quot;issuer_server&quot;&gt;»issuer« server&lt;/h3&gt;
  3526. &lt;div class=&quot;paragraph&quot;&gt;
  3527. &lt;p&gt;There is a server where you can create your JSON web tokens.
  3528. Find it in the »&lt;strong&gt;issuer&lt;/strong&gt;« directory.
  3529. You will need to start it to create your JWTs using a CA.
  3530. It makes use of the &lt;strong&gt;keystore&lt;/strong&gt; module and its private keystore to sign the requested JWT.&lt;/p&gt;
  3531. &lt;/div&gt;
  3532. &lt;div class=&quot;listingblock&quot;&gt;
  3533. &lt;div class=&quot;title&quot;&gt;Getting a token&lt;/div&gt;
  3534. &lt;div class=&quot;content&quot;&gt;
  3535. &lt;pre class=&quot;highlightjs highlight&quot;&gt;&lt;code class=&quot;language-bash hljs&quot; data-lang=&quot;bash&quot;&gt;# shell 1
  3536. ./mvnw -pl issuer -am generate-resources liberty:dev
  3537. # shell 2
  3538. curl \
  3539.  -H &apos;accept: application/json&apos; \
  3540.  -H &apos;content-type: application/json&apos; \
  3541.  -d &apos;{ &quot;username&quot;: &quot;me&quot;, &quot;password&quot;: &quot;me&quot; }&apos; \
  3542.  --url &quot;http://localhost:9081/login?roles=admin&quot;&lt;/code&gt;&lt;/pre&gt;
  3543. &lt;/div&gt;
  3544. &lt;/div&gt;
  3545. &lt;div class=&quot;paragraph&quot;&gt;
  3546. &lt;p&gt;The output will be something like this:&lt;/p&gt;
  3547. &lt;/div&gt;
  3548. &lt;div class=&quot;listingblock&quot;&gt;
  3549. &lt;div class=&quot;title&quot;&gt;Example issuing server output&lt;/div&gt;
  3550. &lt;div class=&quot;content&quot;&gt;
  3551. &lt;pre class=&quot;highlightjs highlight&quot;&gt;&lt;code class=&quot;language-json hljs&quot; data-lang=&quot;json&quot;&gt;{
  3552.  &quot;token&quot;: &quot;ewogICAgImFsZyI6ICJFUzI1NiIKfQ.ewogICAgImlzcyI6ICJodHRwOi8vbG9jYWxob3N0OjkwODEvIiwKICAgICJzdWIiOiAibWUiLAogICAgImlhdCI6IDE2NTA5NTk1NTIsCiAgICAibmJmIjogMTY1MDk1OTU1MiwKICAgICJleHAiOiAxNjUxMDE5NTUyLAogICAgImF1ZCI6ICJzaGlyby1qd3QiLAogICAgInJvbGVzIjogWwogICAgICAgICJhZG1pbiIKICAgIF0KfQ.9Ew6X30zq9t6rUlZ6A28kox4_LJN36dqYZ63eQtQ_ezBOpxeo37VNAmlIjScg7HvJ5VQ5VC0qpb4d_LLnhduLA&quot;
  3553. }&lt;/code&gt;&lt;/pre&gt;
  3554. &lt;/div&gt;
  3555. &lt;/div&gt;
  3556. &lt;div class=&quot;paragraph&quot;&gt;
  3557. &lt;p&gt;If you decode the token fields, you will get the following JSON objects (put into an array for syntax highlighting):&lt;/p&gt;
  3558. &lt;/div&gt;
  3559. &lt;div class=&quot;listingblock&quot;&gt;
  3560. &lt;div class=&quot;content&quot;&gt;
  3561. &lt;pre class=&quot;highlightjs highlight&quot;&gt;&lt;code class=&quot;language-json hljs&quot; data-lang=&quot;json&quot;&gt;[
  3562.  {
  3563.      &quot;alg&quot;: &quot;ES256&quot;
  3564.  },
  3565.  {
  3566.    &quot;iss&quot;: &quot;http://localhost:9081/&quot;,
  3567.    &quot;sub&quot;: &quot;me&quot;,
  3568.    &quot;iat&quot;: 1650959552,
  3569.    &quot;nbf&quot;: 1650959552,
  3570.    &quot;exp&quot;: 1651019552,
  3571.    &quot;aud&quot;: &quot;shiro-jwt&quot;,
  3572.    &quot;roles&quot;: [
  3573.        &quot;admin&quot;
  3574.    ]
  3575.  }
  3576. ]&lt;/code&gt;&lt;/pre&gt;
  3577. &lt;/div&gt;
  3578. &lt;/div&gt;
  3579. &lt;div class=&quot;paragraph&quot;&gt;
  3580. &lt;p&gt;&lt;strong&gt;Hint:&lt;/strong&gt; you can modify the claims by adding roles to the query parameter with the same name.
  3581. Of course this is not a real world example!&lt;/p&gt;
  3582. &lt;/div&gt;
  3583. &lt;/div&gt;
  3584. &lt;div class=&quot;sect2&quot;&gt;
  3585. &lt;h3 id=&quot;finish_server&quot;&gt;»finish« server&lt;/h3&gt;
  3586. &lt;div class=&quot;paragraph&quot;&gt;
  3587. &lt;p&gt;The »&lt;strong&gt;finish&lt;/strong&gt;« directory contains the finished project for reference.&lt;/p&gt;
  3588. &lt;/div&gt;
  3589. &lt;/div&gt;
  3590. &lt;div class=&quot;sect2&quot;&gt;
  3591. &lt;h3 id=&quot;inspecting_the_start_server&quot;&gt;Inspecting the start server&lt;/h3&gt;
  3592. &lt;div class=&quot;paragraph&quot;&gt;
  3593. &lt;p&gt;You might know the start server from my previous article, &lt;a href=&quot;/2022/04/07/jax-rs-endpoints-apache-shiro.adoc&quot;&gt;Securing JAX-RS endpoints using Apache Shiro&lt;/a&gt;.&lt;/p&gt;
  3594. &lt;/div&gt;
  3595. &lt;div class=&quot;paragraph&quot;&gt;
  3596. &lt;p&gt;Please notice I removed the user, password and roles configuration from the &lt;code&gt;shiro.ini&lt;/code&gt; file:&lt;/p&gt;
  3597. &lt;/div&gt;
  3598. &lt;div class=&quot;listingblock&quot;&gt;
  3599. &lt;div class=&quot;content&quot;&gt;
  3600. &lt;pre class=&quot;highlightjs highlight&quot;&gt;&lt;code class=&quot;language-ini hljs&quot; data-lang=&quot;ini&quot;&gt;[main]
  3601.  
  3602. [urls]
  3603. /** = noSessionCreation,authcBasic[permissive]&lt;/code&gt;&lt;/pre&gt;
  3604. &lt;/div&gt;
  3605. &lt;/div&gt;
  3606. &lt;div class=&quot;paragraph&quot;&gt;
  3607. &lt;p&gt;This is the configuration we start with in this tutorial.
  3608. Further changes include:&lt;/p&gt;
  3609. &lt;/div&gt;
  3610. &lt;div class=&quot;ulist&quot;&gt;
  3611. &lt;ul&gt;
  3612. &lt;li&gt;
  3613. &lt;p&gt;Stormtrooper is now a &lt;code&gt;record&lt;/code&gt;.&lt;/p&gt;
  3614. &lt;/li&gt;
  3615. &lt;li&gt;
  3616. &lt;p&gt;Added custom (de-)serialization for the record.&lt;/p&gt;
  3617. &lt;/li&gt;
  3618. &lt;li&gt;
  3619. &lt;p&gt;There is a &lt;code&gt;deleteAllStormTroopers&lt;/code&gt; to set up the tests.&lt;/p&gt;
  3620. &lt;/li&gt;
  3621. &lt;li&gt;
  3622. &lt;p&gt;Most methods in the &lt;code&gt;StormtrooperResource&lt;/code&gt; now return a &lt;code&gt;javax.ws.rs.core.Response&lt;/code&gt; so we can control the http status code.&lt;/p&gt;
  3623. &lt;/li&gt;
  3624. &lt;/ul&gt;
  3625. &lt;/div&gt;
  3626. &lt;div class=&quot;paragraph&quot;&gt;
  3627. &lt;p&gt;Other than that, this should be your average JAX-RS server.&lt;/p&gt;
  3628. &lt;/div&gt;
  3629. &lt;/div&gt;
  3630. &lt;/div&gt;
  3631. &lt;/div&gt;
  3632. &lt;div class=&quot;sect1&quot;&gt;
  3633. &lt;h2 id=&quot;digression_shiro_terms_and_features&quot;&gt;Digression: Shiro Terms and Features&lt;/h2&gt;
  3634. &lt;div class=&quot;sectionbody&quot;&gt;
  3635. &lt;div class=&quot;paragraph&quot;&gt;
  3636. &lt;p&gt;Before we start implementing our Realm, we need to set up some general terms we use in Apache Shiro.&lt;/p&gt;
  3637. &lt;/div&gt;
  3638. &lt;div class=&quot;sect2&quot;&gt;
  3639. &lt;h3 id=&quot;shiro_httpauthenticationfilter&quot;&gt;Shiro HttpAuthenticationFilter&lt;/h3&gt;
  3640. &lt;div class=&quot;paragraph&quot;&gt;
  3641. &lt;p&gt;An &lt;strong&gt;HttpAuthenticationFilter&lt;/strong&gt; is a special filter that Shiro will execute before any attempts are made to check the visitor’s permissions or even before trying to log them in.
  3642. In fact, the &lt;code&gt;authcBasic&lt;/code&gt; filter from above is such an AuthenticatingFilter which implements the &lt;code&gt;Authentication: Basic xxx&lt;/code&gt; header.
  3643. Its real name is &lt;a href=&quot;https://shiro.apache.org/static/1.9.0/apidocs/org/apache/shiro/web/filter/authc/BasicHttpAuthenticationFilter.html&quot;&gt;BasicHttpAuthenticationFilter&lt;/a&gt; and the &lt;code&gt;authcBasic&lt;/code&gt; is just a pre-defined variable name.
  3644. All the filters will do is to parse the authentication header for validity and store its contents into the servlet’s request context.
  3645. This way, the Realm you are authenticating against will be able to log you in.&lt;/p&gt;
  3646. &lt;/div&gt;
  3647. &lt;/div&gt;
  3648. &lt;div class=&quot;sect2&quot;&gt;
  3649. &lt;h3 id=&quot;shiro_credentials&quot;&gt;Shiro Credentials&lt;/h3&gt;
  3650. &lt;div class=&quot;paragraph&quot;&gt;
  3651. &lt;p&gt;&lt;strong&gt;Credentials&lt;/strong&gt; are authentication information or authentication data you send to the server.
  3652. This can be either a username and password token using the above-mentioned &lt;code&gt;authcBasic&lt;/code&gt; filter, or a Bearer token for example.
  3653. The default implementation saves a POJO &lt;a href=&quot;https://shiro.apache.org/static/1.9.0/apidocs/org/apache/shiro/authc/UsernamePasswordToken.html&quot;&gt;&lt;code&gt;UsernamePasswordToken&lt;/code&gt;&lt;/a&gt; into the servlet’s request context, which will (obviously) hold the extracted username and password for later verification.&lt;/p&gt;
  3654. &lt;/div&gt;
  3655. &lt;div class=&quot;paragraph&quot;&gt;
  3656. &lt;p&gt;For our example project we are going to create a specialised version of the &lt;a href=&quot;https://shiro.apache.org/static/1.9.0/apidocs/org/apache/shiro/web/filter/authc/BearerHttpAuthenticationFilter.html&quot;&gt;BearerHttpAuthenticationFilter&lt;/a&gt; which will not store a &lt;code&gt;UsernamePasswordToken&lt;/code&gt;, but instead our own &lt;code&gt;ShiroJsonWebToken&lt;/code&gt;.
  3657. More on that later.&lt;/p&gt;
  3658. &lt;/div&gt;
  3659. &lt;/div&gt;
  3660. &lt;div class=&quot;sect2&quot;&gt;
  3661. &lt;h3 id=&quot;shiro_token&quot;&gt;Shiro Token&lt;/h3&gt;
  3662. &lt;div class=&quot;paragraph&quot;&gt;
  3663. &lt;p&gt;A &lt;strong&gt;Token&lt;/strong&gt; is a class that is returned from parsing the &lt;code&gt;Credentials&lt;/code&gt; using an &lt;code&gt;HttpAuthenticationFilter&lt;/code&gt;.
  3664. This can just be the credentials themselves, wrapped in a POJO.
  3665. Or it could be our own &lt;code&gt;ShiroJsonWebToken&lt;/code&gt; class with some added fields.&lt;/p&gt;
  3666. &lt;/div&gt;
  3667. &lt;/div&gt;
  3668. &lt;div class=&quot;sect2&quot;&gt;
  3669. &lt;h3 id=&quot;shiro_realm&quot;&gt;Shiro Realm&lt;/h3&gt;
  3670. &lt;div class=&quot;paragraph&quot;&gt;
  3671. &lt;p&gt;A &lt;strong&gt;Realm&lt;/strong&gt; is an entity you authenticate against and/or you get your roles and permissions from.
  3672. There are many realms you can combine multiple realms, but this is a topic for another day.
  3673. For this reason (allowing multiple realms to be used in a specific manner and/or order), Realms also have a method which checks if they can parse the given Credentials.
  3674. By default, most Realms will only allow a &lt;code&gt;UsernamePasswordToken&lt;/code&gt;.
  3675. Since we do not get a Username nor a password from a JWT, we need a special Realm which can extract information from the previously mentioned &lt;code&gt;ShiroJsonWebToken&lt;/code&gt;.&lt;/p&gt;
  3676. &lt;/div&gt;
  3677. &lt;/div&gt;
  3678. &lt;div class=&quot;sect2&quot;&gt;
  3679. &lt;h3 id=&quot;shiro_credentialsmatcher&quot;&gt;Shiro CredentialsMatcher&lt;/h3&gt;
  3680. &lt;div class=&quot;paragraph&quot;&gt;
  3681. &lt;p&gt;Every Realm must make use of a &lt;strong&gt;CredentialsMatcher&lt;/strong&gt; which will check if the given AuthenticationToken (e.g. the &lt;code&gt;UsernamePasswordToken&lt;/code&gt; or the &lt;code&gt;ShiroJsonWebToken&lt;/code&gt;) will match the credentials we authenticate against.
  3682. This makes a lot of sense when talking about passwords, because we can just apply the password key derivation function again on the clear text password and check if it matches the stored credentials.&lt;/p&gt;
  3683. &lt;/div&gt;
  3684. &lt;div class=&quot;paragraph&quot;&gt;
  3685. &lt;p&gt;However, JWTs usually come as JWS tokens: Signed pieces of JSON data.
  3686. We can only verify the signature (which is, strictly speaking, not &lt;em&gt;matching&lt;/em&gt;).&lt;/p&gt;
  3687. &lt;/div&gt;
  3688. &lt;/div&gt;
  3689. &lt;div class=&quot;sect2&quot;&gt;
  3690. &lt;h3 id=&quot;shiro_rolepermissionresolver&quot;&gt;Shiro RolePermissionResolver&lt;/h3&gt;
  3691. &lt;div class=&quot;paragraph&quot;&gt;
  3692. &lt;p&gt;The &lt;strong&gt;RolePermissionResolver&lt;/strong&gt; in Shiro is a service class which can resolve roles into permissions.
  3693. Shiro’s permissions are probably the most valuable features next to Shiro’s JAX-RS annotations.&lt;/p&gt;
  3694. &lt;/div&gt;
  3695. &lt;div class=&quot;paragraph&quot;&gt;
  3696. &lt;p&gt;So, how do we resolve roles we get from the JWT/JWS into permissions?
  3697. That highly depends on the applications.
  3698. You could either query them from a database, a static text file or hard-wire them as we do in this example.&lt;/p&gt;
  3699. &lt;/div&gt;
  3700. &lt;/div&gt;
  3701. &lt;/div&gt;
  3702. &lt;/div&gt;
  3703. &lt;div class=&quot;sect1&quot;&gt;
  3704. &lt;h2 id=&quot;implementing_jwts_in_shiro&quot;&gt;Implementing JWTs in Shiro&lt;/h2&gt;
  3705. &lt;div class=&quot;sectionbody&quot;&gt;
  3706. &lt;div class=&quot;paragraph&quot;&gt;
  3707. &lt;p&gt;The first thing we are going to need is the new Authentication Filter.
  3708. While we technically &lt;strong&gt;&lt;em&gt;could&lt;/em&gt;&lt;/strong&gt; use the existing BearerHttpAuthenticationFilter, but creating a custom JWT filter has a few advantages:&lt;/p&gt;
  3709. &lt;/div&gt;
  3710. &lt;div class=&quot;ulist&quot;&gt;
  3711. &lt;ul&gt;
  3712. &lt;li&gt;
  3713. &lt;p&gt;We can extract and store the host and subject separately.&lt;/p&gt;
  3714. &lt;/li&gt;
  3715. &lt;li&gt;
  3716. &lt;p&gt;Validation can occur now or later (or both).&lt;/p&gt;
  3717. &lt;/li&gt;
  3718. &lt;li&gt;
  3719. &lt;p&gt;We can alter the behaviour compared to other Bearer tokens.
  3720. This will effectively allow multiple Bearer realms, depending on the type of the Bearer token.&lt;/p&gt;
  3721. &lt;/li&gt;
  3722. &lt;/ul&gt;
  3723. &lt;/div&gt;
  3724. &lt;div class=&quot;paragraph&quot;&gt;
  3725. &lt;p&gt;But let’s start with the primary objective: Parsing the supplied JWT using jjwt.&lt;/p&gt;
  3726. &lt;/div&gt;
  3727. &lt;div class=&quot;sect2&quot;&gt;
  3728. &lt;h3 id=&quot;implementing_the_jwtparser&quot;&gt;Implementing the JwtParser&lt;/h3&gt;
  3729. &lt;div class=&quot;paragraph&quot;&gt;
  3730. &lt;p&gt;The parser is created in the &lt;a href=&quot;https://github.com/bmarwell/shiro-jwt-showcase/blob/main/finish/src/main/java/io/github/bmarwell/shiro/jwt/service/KeyService.java&quot;&gt;&lt;code&gt;KeyService&lt;/code&gt;&lt;/a&gt; class.
  3731. It contains a specific method &lt;code&gt;public JwtParser createJwtParser()&lt;/code&gt;.
  3732. While at it, &lt;code&gt;mpConfig&lt;/code&gt; is used in the constructor to introduce the issuer name, which must match as well.
  3733. The truststore however is loaded from the &lt;code&gt;shiro.jwt.jaxrs.keystore&lt;/code&gt; dependency.
  3734. It brings its own loader class to avoid complex Classloader handling.
  3735. This truststore holds the public key of the signing certificate which we need for validation.&lt;/p&gt;
  3736. &lt;/div&gt;
  3737. &lt;div class=&quot;paragraph&quot;&gt;
  3738. &lt;p&gt;In this case, using CDI is a complete overkill.
  3739. If you are interested in how to use this class with CDI instead, &lt;a href=&quot;https://github.com/bmarwell/shiro-jwt-showcase/commit/a96c6a3452a38b0678d9f03c77dfbb18fd1a40bf&quot;&gt;look at this commit&lt;/a&gt;.&lt;/p&gt;
  3740. &lt;/div&gt;
  3741. &lt;/div&gt;
  3742. &lt;div class=&quot;sect2&quot;&gt;
  3743. &lt;h3 id=&quot;credentials_filter_jwthttpauthenticator&quot;&gt;Credentials Filter: JwtHttpAuthenticator&lt;/h3&gt;
  3744. &lt;div class=&quot;paragraph&quot;&gt;
  3745. &lt;p&gt;The actual filter to read the JWT is implemented in &lt;a href=&quot;https://github.com/bmarwell/shiro-jwt-showcase/blob/main/finish/src/main/java/io/github/bmarwell/shiro/jwt/shiro/JwtHttpAuthenticator.java&quot;&gt;&lt;code&gt;JwtHttpAuthenticator.java&lt;/code&gt;&lt;/a&gt;.
  3746. It only implements one method with the signature &lt;code&gt;protected AuthenticationToken createToken(ServletRequest request, ServletResponse response)&lt;/code&gt;.
  3747. All it does is to parse the &lt;code&gt;Authorization: Bearer&lt;/code&gt; header for the JWT, checks its validity and stores the result into a &lt;code&gt;ShiroJsonWebToken&lt;/code&gt; (a simple POJO).&lt;/p&gt;
  3748. &lt;/div&gt;
  3749. &lt;div class=&quot;paragraph&quot;&gt;
  3750. &lt;p&gt;One special instruction can be seen, however.
  3751. We create a JWT parser from the &lt;code&gt;KeyStore&lt;/code&gt; class, see above.&lt;/p&gt;
  3752. &lt;/div&gt;
  3753. &lt;div class=&quot;paragraph&quot;&gt;
  3754. &lt;p&gt;To use the filter for all incoming requests, we add a line to &lt;code&gt;shiro.ini&lt;/code&gt; and change the URL filter:&lt;/p&gt;
  3755. &lt;/div&gt;
  3756. &lt;div class=&quot;listingblock&quot;&gt;
  3757. &lt;div class=&quot;content&quot;&gt;
  3758. &lt;pre class=&quot;highlightjs highlight&quot;&gt;&lt;code class=&quot;language-ini hljs&quot; data-lang=&quot;ini&quot;&gt;[main]
  3759. authcJWT = io.github.bmarwell.shiro.jwt.shiro.JwtHttpAuthenticator
  3760.  
  3761. [urls]
  3762. /** = noSessionCreation,authcJWT[permissive]&lt;/code&gt;&lt;/pre&gt;
  3763. &lt;/div&gt;
  3764. &lt;/div&gt;
  3765. &lt;div class=&quot;paragraph&quot;&gt;
  3766. &lt;p&gt;That works in a sense.
  3767. We do get the &lt;code&gt;ShiroJsonWebToken&lt;/code&gt; in our request context, but there is no Realm to handle it yet.&lt;/p&gt;
  3768. &lt;/div&gt;
  3769. &lt;/div&gt;
  3770. &lt;div class=&quot;sect2&quot;&gt;
  3771. &lt;h3 id=&quot;implementing_the_jwtrealm&quot;&gt;Implementing the JwtRealm&lt;/h3&gt;
  3772. &lt;div class=&quot;paragraph&quot;&gt;
  3773. &lt;p&gt;This is the single most important class Shiro+JWT implementation:
  3774. The &lt;a href=&quot;https://github.com/bmarwell/shiro-jwt-showcase/blob/main/finish/src/main/java/io/github/bmarwell/shiro/jwt/shiro/JwtRealm.java&quot;&gt;&lt;code&gt;JwtRealm&lt;/code&gt;&lt;/a&gt; is reading and actually using data from the user-supplied JWT.&lt;/p&gt;
  3775. &lt;/div&gt;
  3776. &lt;div class=&quot;paragraph&quot;&gt;
  3777. &lt;p&gt;For the &lt;code&gt;JwtRealm&lt;/code&gt; I decided to extend the &lt;a href=&quot;https://shiro.apache.org/static/1.9.0/apidocs/org/apache/shiro/realm/AuthorizingRealm.html&quot;&gt;&lt;code&gt;AuthorizingRealm&lt;/code&gt;&lt;/a&gt; class, because it will handle both Authentication and Authorization.&lt;/p&gt;
  3778. &lt;/div&gt;
  3779. &lt;div class=&quot;paragraph&quot;&gt;
  3780. &lt;p&gt;Let’s start with the obvious.&lt;/p&gt;
  3781. &lt;/div&gt;
  3782. &lt;div class=&quot;sect3&quot;&gt;
  3783. &lt;h4 id=&quot;overriding_getname&quot;&gt;Overriding &lt;code&gt;getName()&lt;/code&gt;&lt;/h4&gt;
  3784. &lt;div class=&quot;paragraph&quot;&gt;
  3785. &lt;p&gt;This is less important than the other methods.
  3786. We just need a single, static name for our Realm.
  3787. If we had multiple JwtRealms (yes, this is possible!), we could have a config value injected or set via &lt;code&gt;shiro.ini&lt;/code&gt;.
  3788. But for now, a simple static return will do:&lt;/p&gt;
  3789. &lt;/div&gt;
  3790. &lt;div class=&quot;listingblock&quot;&gt;
  3791. &lt;div class=&quot;content&quot;&gt;
  3792. &lt;pre class=&quot;highlightjs highlight&quot;&gt;&lt;code class=&quot;language-java hljs&quot; data-lang=&quot;java&quot;&gt;  @Override
  3793.  public String getName() {
  3794.    return &quot;jwt&quot;;
  3795.  }&lt;/code&gt;&lt;/pre&gt;
  3796. &lt;/div&gt;
  3797. &lt;/div&gt;
  3798. &lt;/div&gt;
  3799. &lt;div class=&quot;sect3&quot;&gt;
  3800. &lt;h4 id=&quot;overriding_getauthenticationtokenclass&quot;&gt;Overriding &lt;code&gt;getAuthenticationTokenClass()&lt;/code&gt;&lt;/h4&gt;
  3801. &lt;div class=&quot;paragraph&quot;&gt;
  3802. &lt;p&gt;This is a very important class.
  3803. If this method would not return &lt;code&gt;ShiroJsonWebToken.class&lt;/code&gt;, our Realm would be skipped.
  3804. Shiro will only let handle Realms a Token they can understand.&lt;/p&gt;
  3805. &lt;/div&gt;
  3806. &lt;div class=&quot;listingblock&quot;&gt;
  3807. &lt;div class=&quot;content&quot;&gt;
  3808. &lt;pre class=&quot;highlightjs highlight&quot;&gt;&lt;code class=&quot;language-java hljs&quot; data-lang=&quot;java&quot;&gt;  @Override
  3809.  public Class&amp;lt;?&amp;gt; getAuthenticationTokenClass() {
  3810.    return ShiroJsonWebToken.class;
  3811.  }&lt;/code&gt;&lt;/pre&gt;
  3812. &lt;/div&gt;
  3813. &lt;/div&gt;
  3814. &lt;div class=&quot;paragraph&quot;&gt;
  3815. &lt;p&gt;With this method in place, we can implement &lt;code&gt;doGetAuthenticationInfo()&lt;/code&gt;.&lt;/p&gt;
  3816. &lt;/div&gt;
  3817. &lt;/div&gt;
  3818. &lt;div class=&quot;sect3&quot;&gt;
  3819. &lt;h4 id=&quot;overriding_dogetauthenticationinfoauthenticationtoken_token&quot;&gt;Overriding &lt;code&gt;doGetAuthenticationInfo(AuthenticationToken token)&lt;/code&gt;&lt;/h4&gt;
  3820. &lt;div class=&quot;paragraph&quot;&gt;
  3821. &lt;p&gt;The first thing we can do in this method is casting the &lt;code&gt;token&lt;/code&gt; to &lt;code&gt;ShiroJsonWebToken&lt;/code&gt;.
  3822. This is safe and guaranteed by Apache Shiro to work.&lt;/p&gt;
  3823. &lt;/div&gt;
  3824. &lt;div class=&quot;paragraph&quot;&gt;
  3825. &lt;p&gt;From that point on, we can build a &lt;a href=&quot;https://shiro.apache.org/static/1.9.0/apidocs/org/apache/shiro/authc/SimpleAuthenticationInfo.html&quot;&gt;&lt;code&gt;SimpleAuthenticationInfo&lt;/code&gt;&lt;/a&gt; as we already have all trustworthy information at hand:&lt;/p&gt;
  3826. &lt;/div&gt;
  3827. &lt;div class=&quot;listingblock&quot;&gt;
  3828. &lt;div class=&quot;content&quot;&gt;
  3829. &lt;pre class=&quot;highlightjs highlight&quot;&gt;&lt;code class=&quot;language-java hljs&quot; data-lang=&quot;java&quot;&gt;  @Override
  3830.  protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token)
  3831.      throws AuthenticationException {
  3832.    ShiroJsonWebToken jwt = (ShiroJsonWebToken) token;
  3833.  
  3834.    return new SimpleAuthenticationInfo(jwt.getPrincipal(), jwt, getName());
  3835.  }&lt;/code&gt;&lt;/pre&gt;
  3836. &lt;/div&gt;
  3837. &lt;/div&gt;
  3838. &lt;div class=&quot;paragraph&quot;&gt;
  3839. &lt;p&gt;Next, let’s extract the roles from the token.&lt;/p&gt;
  3840. &lt;/div&gt;
  3841. &lt;/div&gt;
  3842. &lt;div class=&quot;sect3&quot;&gt;
  3843. &lt;h4 id=&quot;overriding_dogetauthorizationinfoprincipalcollection_principals&quot;&gt;Overriding &lt;code&gt;doGetAuthorizationInfo(PrincipalCollection principals)&lt;/code&gt;&lt;/h4&gt;
  3844. &lt;div class=&quot;paragraph&quot;&gt;
  3845. &lt;p&gt;Oops… You might notice, we lost our token!
  3846. This method signature does not provide the AuthenticationToken to the method.
  3847. Shiro was built for applications where – after authentication – the authorization info was available with just the principal name (read: UserName) at hand.
  3848. This obviously doesn’t work for a JWT, because in their case the token already contains the authorization information.&lt;/p&gt;
  3849. &lt;/div&gt;
  3850. &lt;div class=&quot;paragraph&quot;&gt;
  3851. &lt;p&gt;So, stepping back a little, how can we work around this?
  3852. Well, at this point you will need some special Java and Shiro knowledge.&lt;/p&gt;
  3853. &lt;/div&gt;
  3854. &lt;div class=&quot;paragraph&quot;&gt;
  3855. &lt;p&gt;Apache Shiro will call both methods in the same thread.
  3856. This already helps us.
  3857. We can declare a static &lt;a href=&quot;https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/ThreadLocal.html&quot;&gt;&lt;code&gt;ThreadLocal&lt;/code&gt;&lt;/a&gt; field, which will hold information even over different instances of our JwtRealm, as long as they are being called from the same Thread.
  3858. So let’s start with declaring such a field.&lt;/p&gt;
  3859. &lt;/div&gt;
  3860. &lt;div class=&quot;listingblock&quot;&gt;
  3861. &lt;div class=&quot;content&quot;&gt;
  3862. &lt;pre class=&quot;highlightjs highlight&quot;&gt;&lt;code class=&quot;language-java hljs&quot; data-lang=&quot;java&quot;&gt;public class JwtRealm extends AuthorizingRealm {
  3863.  private static final ThreadLocal&amp;lt;ShiroJsonWebToken&amp;gt; jwtThreadToken = new ThreadLocal&amp;lt;&amp;gt;();
  3864. }&lt;/code&gt;&lt;/pre&gt;
  3865. &lt;/div&gt;
  3866. &lt;/div&gt;
  3867. &lt;div class=&quot;paragraph&quot;&gt;
  3868. &lt;p&gt;Now let’s get back to the &lt;code&gt;doGetAuthenticationInfo()&lt;/code&gt; method we implemented above.
  3869. It needs to store the token for later retrieval:&lt;/p&gt;
  3870. &lt;/div&gt;
  3871. &lt;div class=&quot;listingblock&quot;&gt;
  3872. &lt;div class=&quot;content&quot;&gt;
  3873. &lt;pre class=&quot;highlightjs highlight&quot;&gt;&lt;code class=&quot;language-java hljs&quot; data-lang=&quot;java&quot;&gt;  @Override
  3874.  protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token)
  3875.      throws AuthenticationException {
  3876.    ShiroJsonWebToken jwt = (ShiroJsonWebToken) token;
  3877.    jwtThreadToken.set(jwt);
  3878.  
  3879.    return new SimpleAuthenticationInfo(jwt.getPrincipal(), jwt, getName());
  3880.  }&lt;/code&gt;&lt;/pre&gt;
  3881. &lt;/div&gt;
  3882. &lt;/div&gt;
  3883. &lt;div class=&quot;paragraph&quot;&gt;
  3884. &lt;p&gt;&lt;em&gt;NOW&lt;/em&gt; we have all the information we need to implement the &lt;a href=&quot;https://shiro.apache.org/static/1.9.0/apidocs/org/apache/shiro/realm/AuthorizingRealm.html#doGetAuthorizationInfo(org.apache.shiro.subject.PrincipalCollection)&quot;&gt;&lt;code&gt;doGetAuthorizationInfo(PrincipalCollection principals)&lt;/code&gt;&lt;/a&gt; method:&lt;/p&gt;
  3885. &lt;/div&gt;
  3886. &lt;div class=&quot;listingblock&quot;&gt;
  3887. &lt;div class=&quot;content&quot;&gt;
  3888. &lt;pre class=&quot;highlightjs highlight&quot;&gt;&lt;code class=&quot;language-java hljs&quot; data-lang=&quot;java&quot;&gt;  @Override
  3889.  protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
  3890.    final ShiroJsonWebToken jsonWebToken = jwtThreadToken.get();
  3891.    final Claims claims = jsonWebToken.getCredentials().getBody();
  3892.    final List&amp;lt;String&amp;gt; roles = Optional.ofNullable(claims.get(&quot;roles&quot;, List.class)).orElse(List.&amp;lt;String&amp;gt;of());
  3893.  
  3894.    return new SimpleAuthorizationInfo(Set.copyOf(roles));
  3895.  }&lt;/code&gt;&lt;/pre&gt;
  3896. &lt;/div&gt;
  3897. &lt;/div&gt;
  3898. &lt;div class=&quot;paragraph&quot;&gt;
  3899. &lt;p&gt;We are just ignoring the principals in this code.
  3900. To make extra sure we are using the correct roles for the correct subject, we could compare the first (primary) principal with the subject form the &lt;code&gt;ShiroJsonWebToken&lt;/code&gt;.
  3901. This step is skipped for brevity.&lt;/p&gt;
  3902. &lt;/div&gt;
  3903. &lt;/div&gt;
  3904. &lt;div class=&quot;sect3&quot;&gt;
  3905. &lt;h4 id=&quot;activating_jwtrealm&quot;&gt;Activating JwtRealm&lt;/h4&gt;
  3906. &lt;div class=&quot;paragraph&quot;&gt;
  3907. &lt;p&gt;Now, let’s use the JwtRealm:&lt;/p&gt;
  3908. &lt;/div&gt;
  3909. &lt;div class=&quot;listingblock&quot;&gt;
  3910. &lt;div class=&quot;title&quot;&gt;One additional line in &lt;code&gt;shiro.ini&lt;/code&gt; for the JwtRealm&lt;/div&gt;
  3911. &lt;div class=&quot;content&quot;&gt;
  3912. &lt;pre class=&quot;highlightjs highlight&quot;&gt;&lt;code class=&quot;language-ini hljs&quot; data-lang=&quot;ini&quot;&gt;[main]
  3913. jwtRealm = io.github.bmarwell.shiro.jwt.shiro.JwtRealm&lt;/code&gt;&lt;/pre&gt;
  3914. &lt;/div&gt;
  3915. &lt;/div&gt;
  3916. &lt;div class=&quot;paragraph&quot;&gt;
  3917. &lt;p&gt;… and voilà, our Realm gets the &lt;code&gt;ShiroJsonWebToken&lt;/code&gt; and can log us in.
  3918. Can it?&lt;/p&gt;
  3919. &lt;/div&gt;
  3920. &lt;/div&gt;
  3921. &lt;/div&gt;
  3922. &lt;div class=&quot;sect2&quot;&gt;
  3923. &lt;h3 id=&quot;credentialsmatcher_for_jwts&quot;&gt;CredentialsMatcher for JWTs&lt;/h3&gt;
  3924. &lt;div class=&quot;paragraph&quot;&gt;
  3925. &lt;p&gt;No, we cannot log in yet.
  3926. Each Realm gets a default CredentialsMatcher class which compares the given Token with the token from the generated AuthenticationInfo.
  3927. Although they are equal in a sense of being a pointer to the same object, the JWS class does not implement an &lt;code&gt;equals&lt;/code&gt; method.
  3928. Thus, the credential comparison fails and we are not logged in.&lt;/p&gt;
  3929. &lt;/div&gt;
  3930. &lt;div class=&quot;paragraph&quot;&gt;
  3931. &lt;p&gt;To fix this, you have two options:&lt;/p&gt;
  3932. &lt;/div&gt;
  3933. &lt;div class=&quot;olist arabic&quot;&gt;
  3934. &lt;ol class=&quot;arabic&quot;&gt;
  3935. &lt;li&gt;
  3936. &lt;p&gt;Deal with the fact that the credentials were already verified early in the Filter and use an &lt;code&gt;AllowAllCredentialsMatcher&lt;/code&gt;.&lt;/p&gt;
  3937. &lt;/li&gt;
  3938. &lt;li&gt;
  3939. &lt;p&gt;Implement our own check.&lt;/p&gt;
  3940. &lt;/li&gt;
  3941. &lt;/ol&gt;
  3942. &lt;/div&gt;
  3943. &lt;div class=&quot;sect3&quot;&gt;
  3944. &lt;h4 id=&quot;disabling_the_credentialsmatcher_not_recommended&quot;&gt;Disabling the CredentialsMatcher (not recommended)&lt;/h4&gt;
  3945. &lt;div class=&quot;admonitionblock caution&quot;&gt;
  3946. &lt;table&gt;
  3947. &lt;tr&gt;
  3948. &lt;td class=&quot;icon&quot;&gt;
  3949. &lt;i class=&quot;fa icon-caution&quot; title=&quot;Caution&quot;&gt;&lt;/i&gt;
  3950. &lt;/td&gt;
  3951. &lt;td class=&quot;content&quot;&gt;
  3952. &lt;div class=&quot;title&quot;&gt;Anti-Pattern: Skipping credential verification&lt;/div&gt;
  3953. &lt;div class=&quot;paragraph&quot;&gt;
  3954. &lt;p&gt;Not verifying credentials is an antipattern.
  3955. We can only do this because we &lt;strong&gt;know&lt;/strong&gt; we verified that very same token earlier in our filter.
  3956. But as applications are becoming more complex, you might get different tokens from different sources which are less trustworth.&lt;/p&gt;
  3957. &lt;/div&gt;
  3958. &lt;/td&gt;
  3959. &lt;/tr&gt;
  3960. &lt;/table&gt;
  3961. &lt;/div&gt;
  3962. &lt;div class=&quot;paragraph&quot;&gt;
  3963. &lt;p&gt;To use option #1, you can use this code snippet:&lt;/p&gt;
  3964. &lt;/div&gt;
  3965. &lt;div class=&quot;listingblock&quot;&gt;
  3966. &lt;div class=&quot;content&quot;&gt;
  3967. &lt;pre class=&quot;highlightjs highlight&quot;&gt;&lt;code class=&quot;language-ini hljs&quot; data-lang=&quot;ini&quot;&gt;[main]
  3968. jwtRealm = io.github.bmarwell.shiro.jwt.shiro.JwtRealm
  3969. anyMatcher = org.apache.shiro.authc.credential.AllowAllCredentialsMatcher
  3970. jwtRealm.credentialsMatcher = $anyMatcher&lt;/code&gt;&lt;/pre&gt;
  3971. &lt;/div&gt;
  3972. &lt;/div&gt;
  3973. &lt;/div&gt;
  3974. &lt;div class=&quot;sect3&quot;&gt;
  3975. &lt;h4 id=&quot;implementing_a_jwtcredentialsmatcher&quot;&gt;Implementing a JwtCredentialsMatcher&lt;/h4&gt;
  3976. &lt;div class=&quot;paragraph&quot;&gt;
  3977. &lt;p&gt;The class &lt;a href=&quot;https://github.com/bmarwell/shiro-jwt-showcase/blob/main/finish/src/main/java/io/github/bmarwell/shiro/jwt/shiro/JwtCheckingCredentialsMatcher.java&quot;&gt;&lt;code&gt;JwtCheckingCredentialsMatcher.java&lt;/code&gt;&lt;/a&gt; implements the credential check by comparing their fields to one and another.
  3978. This is basically the missing &lt;code&gt;equals&lt;/code&gt; method in the JWS class.
  3979. However, it is still not re-verifying the token when tokens could come unverified from different sources, not just our own JwtHttpAuthenticator.&lt;/p&gt;
  3980. &lt;/div&gt;
  3981. &lt;div class=&quot;admonitionblock caution&quot;&gt;
  3982. &lt;table&gt;
  3983. &lt;tr&gt;
  3984. &lt;td class=&quot;icon&quot;&gt;
  3985. &lt;i class=&quot;fa icon-caution&quot; title=&quot;Caution&quot;&gt;&lt;/i&gt;
  3986. &lt;/td&gt;
  3987. &lt;td class=&quot;content&quot;&gt;
  3988. &lt;div class=&quot;title&quot;&gt;Do not just copy this class!&lt;/div&gt;
  3989. &lt;div class=&quot;paragraph&quot;&gt;
  3990. &lt;p&gt;Please do not copy the &lt;code&gt;JwtCheckingCredentialsMatcher.java&lt;/code&gt; file.
  3991. It lacks signature verification for brevity.
  3992. Inject the JwtParser again using either CDI or other means.&lt;/p&gt;
  3993. &lt;/div&gt;
  3994. &lt;/td&gt;
  3995. &lt;/tr&gt;
  3996. &lt;/table&gt;
  3997. &lt;/div&gt;
  3998. &lt;div class=&quot;paragraph&quot;&gt;
  3999. &lt;p&gt;To use it, just add it to shiro.ini likewise:&lt;/p&gt;
  4000. &lt;/div&gt;
  4001. &lt;div class=&quot;listingblock&quot;&gt;
  4002. &lt;div class=&quot;title&quot;&gt;Adding a JwtChecker to the JwtRealm&lt;/div&gt;
  4003. &lt;div class=&quot;content&quot;&gt;
  4004. &lt;pre class=&quot;highlightjs highlight&quot;&gt;&lt;code class=&quot;language-ini hljs&quot; data-lang=&quot;ini&quot;&gt;[main]
  4005. jwtRealm = io.github.bmarwell.shiro.jwt.shiro.JwtRealm
  4006. jwtChecker = io.github.bmarwell.shiro.jwt.shiro.JwtCheckingCredentialsMatcher
  4007. jwtRealm.credentialsMatcher = $jwtChecker&lt;/code&gt;&lt;/pre&gt;
  4008. &lt;/div&gt;
  4009. &lt;/div&gt;
  4010. &lt;div class=&quot;paragraph&quot;&gt;
  4011. &lt;p&gt;The CredentialsMatcher I implemented will do the following things:&lt;/p&gt;
  4012. &lt;/div&gt;
  4013. &lt;div class=&quot;ulist&quot;&gt;
  4014. &lt;ul&gt;
  4015. &lt;li&gt;
  4016. &lt;p&gt;Check if it previously has been validated.
  4017. This is important, since we already got the roles from it.&lt;/p&gt;
  4018. &lt;/li&gt;
  4019. &lt;li&gt;
  4020. &lt;p&gt;Re-Parse the token (that is a potential performance issue!) and compare the fields header, body and signature for equality.&lt;/p&gt;
  4021. &lt;/li&gt;
  4022. &lt;/ul&gt;
  4023. &lt;/div&gt;
  4024. &lt;/div&gt;
  4025. &lt;/div&gt;
  4026. &lt;/div&gt;
  4027. &lt;/div&gt;
  4028. &lt;div class=&quot;sect1&quot;&gt;
  4029. &lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
  4030. &lt;div class=&quot;sectionbody&quot;&gt;
  4031. &lt;div class=&quot;paragraph&quot;&gt;
  4032. &lt;p&gt;That’s about it!
  4033. To wrap it up, we had to create three classes:
  4034. * A new HttpAuthenticationFilter which intercepts, verifies and wraps the signed JWT into the &lt;code&gt;ShiroJsonWebToken&lt;/code&gt;.
  4035. * The Realm which can parse the &lt;code&gt;ShiroJsonWebToken&lt;/code&gt;
  4036. * optionally a CredentialsMatcher which re-checks the signature and JWT.
  4037. * optionally a RolePermissionResolver class if you use permissions rather than roles.&lt;/p&gt;
  4038. &lt;/div&gt;
  4039. &lt;div class=&quot;paragraph&quot;&gt;
  4040. &lt;p&gt;This is our &lt;a href=&quot;https://github.com/bmarwell/shiro-jwt-showcase/blob/main/finish/src/main/webapp/shiro.ini&quot;&gt;final &lt;code&gt;shiro.ini&lt;/code&gt; configuration file&lt;/a&gt;:&lt;/p&gt;
  4041. &lt;/div&gt;
  4042. &lt;div class=&quot;listingblock&quot;&gt;
  4043. &lt;div class=&quot;content&quot;&gt;
  4044. &lt;pre class=&quot;highlightjs highlight&quot;&gt;&lt;code class=&quot;language-ini hljs&quot; data-lang=&quot;ini&quot;&gt;[main]
  4045. jwtRealm = io.github.bmarwell.shiro.jwt.shiro.JwtRealm
  4046. jwtChecker = io.github.bmarwell.shiro.jwt.shiro.JwtCheckingCredentialsMatcher
  4047. jwtRealm.credentialsMatcher = $jwtChecker
  4048. jwtStaticRolePermissionResolver = io.github.bmarwell.shiro.jwt.shiro.StaticJwtRolePermissionResolver
  4049. jwtRealm.rolePermissionResolver = $jwtStaticRolePermissionResolver
  4050.  
  4051. authcJWT = io.github.bmarwell.shiro.jwt.shiro.JwtHttpAuthenticator
  4052.  
  4053. [urls]
  4054. /** = noSessionCreation,authcJWT[permissive]&lt;/code&gt;&lt;/pre&gt;
  4055. &lt;/div&gt;
  4056. &lt;/div&gt;
  4057. &lt;div class=&quot;paragraph&quot;&gt;
  4058. &lt;p&gt;If you leave out the optional bits, we are down to two classes and 4 additional lines.
  4059. I hope this was not too hard to understand.
  4060. If you have any questions, feel free to reach out to us on Twitter:&lt;/p&gt;
  4061. &lt;/div&gt;
  4062. &lt;div class=&quot;ulist&quot;&gt;
  4063. &lt;ul&gt;
  4064. &lt;li&gt;
  4065. &lt;p&gt;&lt;a href=&quot;https://twitter.com/ApacheShiro&quot;&gt;@ApacheShiro&lt;/a&gt; – the official Apache Shiro Twitter account.&lt;/p&gt;
  4066. &lt;/li&gt;
  4067. &lt;li&gt;
  4068. &lt;p&gt;&lt;a href=&quot;https://twitter.com/bmarwell&quot;&gt;@bmarwell&lt;/a&gt; – me&lt;/p&gt;
  4069. &lt;/li&gt;
  4070. &lt;li&gt;
  4071. &lt;p&gt;&lt;a href=&quot;https://twitter.com/briandemers&quot;&gt;@briandemers&lt;/a&gt; – Brian Demers, who wrote the original JAX-RS example.&lt;/p&gt;
  4072. &lt;/li&gt;
  4073. &lt;/ul&gt;
  4074. &lt;/div&gt;
  4075. &lt;div class=&quot;paragraph&quot;&gt;
  4076. &lt;p&gt;Or reach out to us on the &lt;a href=&quot;https://shiro.apache.org/mailing-lists.html&quot;&gt;Apache Shiro &lt;strong&gt;user&lt;/strong&gt; mailing list&lt;/a&gt;.&lt;/p&gt;
  4077. &lt;/div&gt;
  4078. &lt;div class=&quot;paragraph&quot;&gt;
  4079. &lt;p&gt;Fun fact: Both Apache Shiro and JJWT were started by Les Hazlewood.&lt;/p&gt;
  4080. &lt;/div&gt;
  4081. &lt;/div&gt;
  4082. &lt;/div&gt;
  4083. &lt;div class=&quot;sect1&quot;&gt;
  4084. &lt;h2 id=&quot;further_reading&quot;&gt;Further reading&lt;/h2&gt;
  4085. &lt;div class=&quot;sectionbody&quot;&gt;
  4086. &lt;div class=&quot;dlist&quot;&gt;
  4087. &lt;dl&gt;
  4088. &lt;dt class=&quot;hdlist1&quot;&gt;IBM: Configuring the MicroProfile JSON Web Token&lt;/dt&gt;
  4089. &lt;dd&gt;
  4090. &lt;p&gt;&lt;a href=&quot;https://www.ibm.com/docs/en/was-liberty/base?topic=liberty-configuring-microprofile-json-web-token&quot; class=&quot;bare&quot;&gt;https://www.ibm.com/docs/en/was-liberty/base?topic=liberty-configuring-microprofile-json-web-token&lt;/a&gt;&lt;/p&gt;
  4091. &lt;/dd&gt;
  4092. &lt;dt class=&quot;hdlist1&quot;&gt;Open Liberty: MicroProfile Config 2.0&lt;/dt&gt;
  4093. &lt;dd&gt;
  4094. &lt;p&gt;&lt;a href=&quot;https://openliberty.io/blog/2021/03/31/microprofile-config-2.0.html&quot; class=&quot;bare&quot;&gt;https://openliberty.io/blog/2021/03/31/microprofile-config-2.0.html&lt;/a&gt;&lt;/p&gt;
  4095. &lt;/dd&gt;
  4096. &lt;dt class=&quot;hdlist1&quot;&gt;jwt.io: Online Debugger and Verifier&lt;/dt&gt;
  4097. &lt;dd&gt;
  4098. &lt;p&gt;&lt;a href=&quot;https://jwt.io/&quot; class=&quot;bare&quot;&gt;https://jwt.io/&lt;/a&gt;&lt;/p&gt;
  4099. &lt;/dd&gt;
  4100. &lt;/dl&gt;
  4101. &lt;/div&gt;
  4102. &lt;/div&gt;
  4103. &lt;/div&gt;
  4104.    </content>
  4105.  </entry>
  4106.  
  4107.  <entry>
  4108.    <!-- lang="en-GB"  -->
  4109.    <title>Securing JAX-RS endpoints using Apache Shiro</title>
  4110.    <link href="https://blog.bmarwell.de/2022/04/07/jax-rs-endpoints-apache-shiro.html"/>
  4111.    <id>https://blog.bmarwell.de/2022/04/07/jax-rs-endpoints-apache-shiro.html</id>
  4112.    <published>2022-04-07T19:44:00Z</published>
  4113.    <updated>2022-04-07T19:44:00Z</updated>
  4114.    <author>
  4115.      <name>Benjamin Marwell</name>
  4116.    </author>
  4117.    <content type="html">
  4118.      &lt;div id=&quot;toc&quot; class=&quot;toc&quot;&gt;
  4119. &lt;div id=&quot;toctitle&quot;&gt;Table of Contents&lt;/div&gt;
  4120. &lt;ul class=&quot;sectlevel1&quot;&gt;
  4121. &lt;li&gt;&lt;a href=&quot;#apache_shiro_the_java_library&quot;&gt;Apache Shiro: The Java Library&lt;/a&gt;&lt;/li&gt;
  4122. &lt;li&gt;&lt;a href=&quot;#knowledge_and_prerequisites_for_this_apache_shiro_jax_rs_tutorial&quot;&gt;Knowledge and Prerequisites for this Apache Shiro JAX-RS tutorial&lt;/a&gt;&lt;/li&gt;
  4123. &lt;li&gt;&lt;a href=&quot;#shiro_for_jax_rs_overview&quot;&gt;Shiro for JAX-RS: Overview&lt;/a&gt;
  4124. &lt;ul class=&quot;sectlevel2&quot;&gt;
  4125. &lt;li&gt;&lt;a href=&quot;#shiro_for_jax_rs&quot;&gt;Shiro for JAX-RS&lt;/a&gt;&lt;/li&gt;
  4126. &lt;li&gt;&lt;a href=&quot;#preparing_a_shiro_jax_rs_endpoint&quot;&gt;Preparing a Shiro JAX-RS endpoint&lt;/a&gt;&lt;/li&gt;
  4127. &lt;li&gt;&lt;a href=&quot;#implementing_a_simple_jax_rs_endpoint_using_shiro&quot;&gt;Implementing a simple JAX-RS endpoint using Shiro&lt;/a&gt;&lt;/li&gt;
  4128. &lt;li&gt;&lt;a href=&quot;#creating_an_admin_user&quot;&gt;Creating an admin user&lt;/a&gt;&lt;/li&gt;
  4129. &lt;/ul&gt;
  4130. &lt;/li&gt;
  4131. &lt;li&gt;&lt;a href=&quot;#testing_your_shiro_endpoints&quot;&gt;Testing your Shiro Endpoints&lt;/a&gt;&lt;/li&gt;
  4132. &lt;li&gt;&lt;a href=&quot;#conclusions&quot;&gt;Conclusions&lt;/a&gt;&lt;/li&gt;
  4133. &lt;li&gt;&lt;a href=&quot;#alternatives_to_apache_shiro&quot;&gt;Alternatives to Apache Shiro&lt;/a&gt;&lt;/li&gt;
  4134. &lt;li&gt;&lt;a href=&quot;#further_reading&quot;&gt;Further reading&lt;/a&gt;&lt;/li&gt;
  4135. &lt;/ul&gt;
  4136. &lt;/div&gt;
  4137. &lt;div id=&quot;preamble&quot;&gt;
  4138. &lt;div class=&quot;sectionbody&quot;&gt;
  4139. &lt;div class=&quot;paragraph&quot;&gt;
  4140. &lt;p&gt;&lt;a href=&quot;https://shiro.apache.org&quot;&gt;&lt;strong&gt;Apache Shiro&lt;/strong&gt;&lt;/a&gt; is a powerful Java Security Toolkit, used by Java developers around the world to secure their applications.
  4141. While Apache Shiro’s focus is on broad usability, it does excel in specific use cases.
  4142. This article will give you a broad overview of what Apache Shiro is used for and where it excels, especially compared to other frameworks.&lt;/p&gt;
  4143. &lt;/div&gt;
  4144. &lt;/div&gt;
  4145. &lt;/div&gt;
  4146. &lt;div class=&quot;sect1&quot;&gt;
  4147. &lt;h2 id=&quot;apache_shiro_the_java_library&quot;&gt;Apache Shiro: The Java Library&lt;/h2&gt;
  4148. &lt;div class=&quot;sectionbody&quot;&gt;
  4149. &lt;div class=&quot;paragraph&quot;&gt;
  4150. &lt;p&gt;If you ask yourself »What is Apache Shiro?«, well, this is too broad of a question.
  4151. Apache Shiro is a Java library, or more specifically a collection of Java libraries you can include into your application.
  4152. You can include it in all kind of applications: Java Web Applications (&lt;code&gt;.war&lt;/code&gt;), Java Enterprise Applications (&lt;code&gt;.ear&lt;/code&gt;) and even standalone applications (&lt;code&gt;.jar&lt;/code&gt;)!&lt;/p&gt;
  4153. &lt;/div&gt;
  4154. &lt;div class=&quot;paragraph&quot;&gt;
  4155. &lt;p&gt;So, »what is Apache Shiro«?&amp;#8201;&amp;#8212;&amp;#8201;A Java Library to secure any Java Application using permissions, roles and authentication of ussers.
  4156. Read the next paragraph to see how to use it in your JAX-RS application.&lt;/p&gt;
  4157. &lt;/div&gt;
  4158. &lt;/div&gt;
  4159. &lt;/div&gt;
  4160. &lt;div class=&quot;sect1&quot;&gt;
  4161. &lt;h2 id=&quot;knowledge_and_prerequisites_for_this_apache_shiro_jax_rs_tutorial&quot;&gt;Knowledge and Prerequisites for this Apache Shiro JAX-RS tutorial&lt;/h2&gt;
  4162. &lt;div class=&quot;sectionbody&quot;&gt;
  4163. &lt;div class=&quot;paragraph&quot;&gt;
  4164. &lt;p&gt;You need to know about the following things:&lt;/p&gt;
  4165. &lt;/div&gt;
  4166. &lt;div class=&quot;ulist&quot;&gt;
  4167. &lt;ul&gt;
  4168. &lt;li&gt;
  4169. &lt;p&gt;How to configure your project using Apache Maven (or any similar java build tool like Gradle)&lt;/p&gt;
  4170. &lt;/li&gt;
  4171. &lt;li&gt;
  4172. &lt;p&gt;How to set up a &lt;code&gt;.war&lt;/code&gt; project&lt;/p&gt;
  4173. &lt;/li&gt;
  4174. &lt;li&gt;
  4175. &lt;p&gt;How to set up a JAX-RS application using annotations&lt;/p&gt;
  4176. &lt;/li&gt;
  4177. &lt;li&gt;
  4178. &lt;p&gt;How JAX-RS endpoints work&lt;/p&gt;
  4179. &lt;/li&gt;
  4180. &lt;li&gt;
  4181. &lt;p&gt;How to run your project on your favourite application serer&lt;/p&gt;
  4182. &lt;/li&gt;
  4183. &lt;li&gt;
  4184. &lt;p&gt;How to query your endpoints (e.g. using curl, Insomnia, Postman etc.)&lt;/p&gt;
  4185. &lt;/li&gt;
  4186. &lt;/ul&gt;
  4187. &lt;/div&gt;
  4188. &lt;/div&gt;
  4189. &lt;/div&gt;
  4190. &lt;div class=&quot;sect1&quot;&gt;
  4191. &lt;h2 id=&quot;shiro_for_jax_rs_overview&quot;&gt;Shiro for JAX-RS: Overview&lt;/h2&gt;
  4192. &lt;div class=&quot;sectionbody&quot;&gt;
  4193. &lt;div class=&quot;paragraph&quot;&gt;
  4194. &lt;p&gt;The first thing you will need in any case is a file &lt;code&gt;shiro.ini&lt;/code&gt;.
  4195. This file defines some basic rules for Shiro and can be extended later.&lt;/p&gt;
  4196. &lt;/div&gt;
  4197. &lt;div class=&quot;paragraph&quot;&gt;
  4198. &lt;p&gt;To be able to use Apache Shiro in your Maven project, you will need a few dependencies:&lt;/p&gt;
  4199. &lt;/div&gt;
  4200. &lt;div class=&quot;listingblock&quot;&gt;
  4201. &lt;div class=&quot;content&quot;&gt;
  4202. &lt;pre class=&quot;highlightjs highlight&quot;&gt;&lt;code class=&quot;language-xml hljs&quot; data-lang=&quot;xml&quot;&gt;  &amp;lt;dependencies&amp;gt;
  4203.    &amp;lt;dependency&amp;gt;
  4204.      &amp;lt;groupId&amp;gt;org.apache.shiro&amp;lt;/groupId&amp;gt;
  4205.      &amp;lt;artifactId&amp;gt;shiro-core&amp;lt;/artifactId&amp;gt;
  4206.      &amp;lt;version&amp;gt;${dependency.shiro.version}&amp;lt;/version&amp;gt;
  4207.    &amp;lt;/dependency&amp;gt;
  4208.    &amp;lt;dependency&amp;gt;
  4209.      &amp;lt;groupId&amp;gt;org.apache.shiro&amp;lt;/groupId&amp;gt;
  4210.      &amp;lt;artifactId&amp;gt;shiro-web&amp;lt;/artifactId&amp;gt;
  4211.      &amp;lt;version&amp;gt;${dependency.shiro.version}&amp;lt;/version&amp;gt;
  4212.    &amp;lt;/dependency&amp;gt;
  4213.  &amp;lt;/dependencies&amp;gt;&lt;/code&gt;&lt;/pre&gt;
  4214. &lt;/div&gt;
  4215. &lt;/div&gt;
  4216. &lt;div class=&quot;paragraph&quot;&gt;
  4217. &lt;p&gt;For the start, the first thing we case about is to tell Apache Shiro which web paths to secure.
  4218. Big surprise: You want it to (potentially) secure ALL paths, even your login!
  4219. The fine-grained »what does Shiro allow the user to do« will be set up later.&lt;/p&gt;
  4220. &lt;/div&gt;
  4221. &lt;div class=&quot;paragraph&quot;&gt;
  4222. &lt;p&gt;The following file is located in the classpath root.&lt;/p&gt;
  4223. &lt;/div&gt;
  4224. &lt;div class=&quot;listingblock&quot;&gt;
  4225. &lt;div class=&quot;title&quot;&gt;A shiro.ini starter&lt;/div&gt;
  4226. &lt;div class=&quot;content&quot;&gt;
  4227. &lt;pre class=&quot;highlightjs highlight&quot;&gt;&lt;code class=&quot;language-ini hljs&quot; data-lang=&quot;ini&quot;&gt;[main]
  4228.  
  4229.  
  4230. [urls]
  4231. /** = noSessionCreation,authcBasic[permissive]&lt;/code&gt;&lt;/pre&gt;
  4232. &lt;/div&gt;
  4233. &lt;/div&gt;
  4234. &lt;div class=&quot;paragraph&quot;&gt;
  4235. &lt;p&gt;Now, we allow to check for permissions to request a specific resource.
  4236. As with any modern application, we &lt;strong&gt;do not create a session&lt;/strong&gt; (more on that later).
  4237. The next thing to look out for is &lt;code&gt;authcBasic&lt;/code&gt;.
  4238. It tells Shiro you can authenticate (tell Shiro who you are) using a HTTP header.
  4239. But if we stopped there, Shiro would &lt;strong&gt;require&lt;/strong&gt; this header, even for displaying a login page
  4240. or the login resource, which does not make any sense. Hence we added the &lt;code&gt;[permissive]&lt;/code&gt; parameter,
  4241. which tells Shiro that a login is not mandatory by default.
  4242. On the downside, we have to tell Shiro for each resource that an authenticated user is necessary, when applicable.&lt;/p&gt;
  4243. &lt;/div&gt;
  4244. &lt;div class=&quot;admonitionblock important&quot;&gt;
  4245. &lt;table&gt;
  4246. &lt;tr&gt;
  4247. &lt;td class=&quot;icon&quot;&gt;
  4248. &lt;i class=&quot;fa icon-important&quot; title=&quot;Important&quot;&gt;&lt;/i&gt;
  4249. &lt;/td&gt;
  4250. &lt;td class=&quot;content&quot;&gt;
  4251. &lt;div class=&quot;title&quot;&gt;The very basics of Shiro&lt;/div&gt;
  4252. &lt;div class=&quot;paragraph&quot;&gt;
  4253. &lt;p&gt;While the paragraph above contains a lot of dense information, be sure to read it carefully.
  4254. It contains a lot of valuable information which is needed to understand the following sections.&lt;/p&gt;
  4255. &lt;/div&gt;
  4256. &lt;div class=&quot;paragraph&quot;&gt;
  4257. &lt;p&gt;Repeat it and try to explain it in easy words to someone else in simple English.
  4258. If you cannot do it, read it over and try again until you succeed.&lt;/p&gt;
  4259. &lt;/div&gt;
  4260. &lt;/td&gt;
  4261. &lt;/tr&gt;
  4262. &lt;/table&gt;
  4263. &lt;/div&gt;
  4264. &lt;div class=&quot;paragraph&quot;&gt;
  4265. &lt;p&gt;But to be able to test Apache Shiro with JAX-RS, we might want to add a user.
  4266. For sake of easiness, let’s start with a hard-coded user.
  4267. In practice later on, you will want to add authentication against another source, e.g. a Database or LDAP or Active Directory.&lt;/p&gt;
  4268. &lt;/div&gt;
  4269. &lt;div class=&quot;sect2&quot;&gt;
  4270. &lt;h3 id=&quot;shiro_for_jax_rs&quot;&gt;Shiro for JAX-RS&lt;/h3&gt;
  4271. &lt;div class=&quot;paragraph&quot;&gt;
  4272. &lt;p&gt;JAX-RS is &lt;em&gt;the&lt;/em&gt; number one web technology for Java right now (in my opinion).
  4273. It allows you to create simple and predictable endpoints that output only data, but no HTML code.
  4274. The data can be encoded in any form you like.
  4275. While JSON is the most common data encoding, JAX-RS (Restful endpoints) are not restricted to it.
  4276. Other valid options are TOML, YAML, XML and even Google Protobuf would work!&lt;/p&gt;
  4277. &lt;/div&gt;
  4278. &lt;div class=&quot;paragraph&quot;&gt;
  4279. &lt;p&gt;All set?
  4280. Let’s dive in right into the code!&lt;/p&gt;
  4281. &lt;/div&gt;
  4282. &lt;/div&gt;
  4283. &lt;div class=&quot;sect2&quot;&gt;
  4284. &lt;h3 id=&quot;preparing_a_shiro_jax_rs_endpoint&quot;&gt;Preparing a Shiro JAX-RS endpoint&lt;/h3&gt;
  4285. &lt;div class=&quot;paragraph&quot;&gt;
  4286. &lt;p&gt;Let’s update our dependencies first.
  4287. Shiro’s JAX-RS-dependency contains the other dependencies I mentioned earlier:&lt;/p&gt;
  4288. &lt;/div&gt;
  4289. &lt;div class=&quot;listingblock&quot;&gt;
  4290. &lt;div class=&quot;content&quot;&gt;
  4291. &lt;pre class=&quot;highlightjs highlight&quot;&gt;&lt;code class=&quot;language-xml hljs&quot; data-lang=&quot;xml&quot;&gt;  &amp;lt;dependencies&amp;gt;
  4292.    &amp;lt;dependency&amp;gt;
  4293.      &amp;lt;groupId&amp;gt;org.apache.shiro&amp;lt;/groupId&amp;gt;
  4294.      &amp;lt;artifactId&amp;gt;shiro-jaxrs&amp;lt;/artifactId&amp;gt;
  4295.      &amp;lt;version&amp;gt;${dependency.shiro.version}&amp;lt;/version&amp;gt;
  4296.    &amp;lt;/dependency&amp;gt;
  4297.  &amp;lt;/dependencies&amp;gt;&lt;/code&gt;&lt;/pre&gt;
  4298. &lt;/div&gt;
  4299. &lt;/div&gt;
  4300. &lt;div class=&quot;paragraph&quot;&gt;
  4301. &lt;p&gt;To make Shiro being picked up, you will need three additional things:&lt;/p&gt;
  4302. &lt;/div&gt;
  4303. &lt;div class=&quot;dlist&quot;&gt;
  4304. &lt;dl&gt;
  4305. &lt;dt class=&quot;hdlist1&quot;&gt;A ShiroServletFilter&lt;/dt&gt;
  4306. &lt;dd&gt;
  4307. &lt;p&gt;A class extending &lt;code&gt;ShiroFilter&lt;/code&gt; which will implement the servlet filter.
  4308. All JAX-RS endpoints are servlets in disguise, so a servlet filter will be executed before the execution is handed over to the JAX-RS class.
  4309. We also define which events to listen to.&lt;/p&gt;
  4310. &lt;/dd&gt;
  4311. &lt;dt class=&quot;hdlist1&quot;&gt;A Shiro EnvironmentListener&lt;/dt&gt;
  4312. &lt;dd&gt;
  4313. &lt;p&gt;This class will be a listener on application startup which initializes Shiro once.
  4314. Actually, this Servlet Listener will invoke the loading of the &lt;code&gt;shiro.ini&lt;/code&gt; file.&lt;/p&gt;
  4315. &lt;/dd&gt;
  4316. &lt;dt class=&quot;hdlist1&quot;&gt;A ShiroJaxRsFeature&lt;/dt&gt;
  4317. &lt;dd&gt;
  4318. &lt;p&gt;JAX-RS annotations need to be registered as a feature.
  4319. While the &lt;code&gt;shiro-jaxrs&lt;/code&gt; dependency ships such a class, we need to extend it, so it will be picked up.&lt;/p&gt;
  4320. &lt;/dd&gt;
  4321. &lt;/dl&gt;
  4322. &lt;/div&gt;
  4323. &lt;div class=&quot;paragraph&quot;&gt;
  4324. &lt;p&gt;There are alternative approaches which do the same:&lt;/p&gt;
  4325. &lt;/div&gt;
  4326. &lt;div class=&quot;ulist&quot;&gt;
  4327. &lt;ul&gt;
  4328. &lt;li&gt;
  4329. &lt;p&gt;Adding the filter to the &lt;code&gt;web.xml&lt;/code&gt; or importing the &lt;code&gt;shiro-servlet&lt;/code&gt; dependency, which contains this very same snippet.&lt;/p&gt;
  4330. &lt;/li&gt;
  4331. &lt;li&gt;
  4332. &lt;p&gt;Adding the listener to the &lt;code&gt;web.xml&lt;/code&gt; or importing the &lt;code&gt;shiro-servlet&lt;/code&gt; dependency, which contains this very same snippet.&lt;/p&gt;
  4333. &lt;/li&gt;
  4334. &lt;li&gt;
  4335. &lt;p&gt;Adding Shiro’s feature class (&lt;code&gt;org.apache.shiro.web.jaxrs.ShiroFeature&lt;/code&gt;) to your Java class extending &lt;code&gt;javax.ws.rs.core.Application&lt;/code&gt;.
  4336. But this would force you to declare all JAX-RS classes manually, since a non-empty Set would disable auto-discovery.&lt;/p&gt;
  4337. &lt;/li&gt;
  4338. &lt;/ul&gt;
  4339. &lt;/div&gt;
  4340. &lt;div class=&quot;paragraph&quot;&gt;
  4341. &lt;p&gt;The implementations are quite simple, as they only extend and annotate Shiro’s existing classes:&lt;/p&gt;
  4342. &lt;/div&gt;
  4343. &lt;script src=&quot;https://gist.github.com/bmarwell/213932fe9187c1cc3fa8ca46373a0f29.js&quot;&gt;&lt;/script&gt;
  4344. &lt;/div&gt;
  4345. &lt;div class=&quot;sect2&quot;&gt;
  4346. &lt;h3 id=&quot;implementing_a_simple_jax_rs_endpoint_using_shiro&quot;&gt;Implementing a simple JAX-RS endpoint using Shiro&lt;/h3&gt;
  4347. &lt;div class=&quot;paragraph&quot;&gt;
  4348. &lt;p&gt;Now that the setup is done, let’s create an endpoint and add our Shiro annotations.
  4349. Let us consider your existing endpoint which can output all Storm Troopers in your database:&lt;/p&gt;
  4350. &lt;/div&gt;
  4351. &lt;script src=&quot;https://gist.github.com/bmarwell/a329e5071fa45cdd369891ac04c684d8.js&quot;&gt;&lt;/script&gt;
  4352. &lt;div class=&quot;paragraph&quot;&gt;
  4353. &lt;p&gt;For Shiro to do it’s work, you will need two annotations.&lt;/p&gt;
  4354. &lt;/div&gt;
  4355. &lt;div class=&quot;olist arabic&quot;&gt;
  4356. &lt;ol class=&quot;arabic&quot;&gt;
  4357. &lt;li&gt;
  4358. &lt;p&gt;Since all your endpoints in this class are only available to registered users, add the annotation &lt;code&gt;@org.apache.shiro.authz.annotation.RequiresUser&lt;/code&gt; to the class.&lt;/p&gt;
  4359. &lt;/li&gt;
  4360. &lt;li&gt;
  4361. &lt;p&gt;Not every registered user can read the known storm troopers.
  4362. Only users with the permission &lt;code&gt;troopers:read&lt;/code&gt; may do this.
  4363. Imagine this is a permission implicitly granted to all admins and stormtrooper managers.
  4364. We need to add &lt;code&gt;@org.apache.shiro.authz.annotation.RequiresPermissions(&quot;troopers:read&quot;)&lt;/code&gt; for this to work.&lt;/p&gt;
  4365. &lt;/li&gt;
  4366. &lt;/ol&gt;
  4367. &lt;/div&gt;
  4368. &lt;div class=&quot;paragraph&quot;&gt;
  4369. &lt;p&gt;The modified snippet looks like this:&lt;/p&gt;
  4370. &lt;/div&gt;
  4371. &lt;script src=&quot;https://gist.github.com/bmarwell/83846bd628696c199354d6089d56d47d.js&quot;&gt;&lt;/script&gt;
  4372. &lt;div class=&quot;paragraph&quot;&gt;
  4373. &lt;p&gt;If you now try to read this resource, you will get a 401 Unauthorized response,
  4374. indicating the need for authentication as set up by adding the user requirement.&lt;/p&gt;
  4375. &lt;/div&gt;
  4376. &lt;div class=&quot;paragraph&quot;&gt;
  4377. &lt;p&gt;We do not have a user yet, so let us extend our &lt;code&gt;shiro.ini&lt;/code&gt; file.&lt;/p&gt;
  4378. &lt;/div&gt;
  4379. &lt;/div&gt;
  4380. &lt;div class=&quot;sect2&quot;&gt;
  4381. &lt;h3 id=&quot;creating_an_admin_user&quot;&gt;Creating an admin user&lt;/h3&gt;
  4382. &lt;div class=&quot;paragraph&quot;&gt;
  4383. &lt;p&gt;As mentioned previously, let us consider a simple and hard-coded authentication.
  4384. Authentication by other means (LDAP, AD, DB) will be covered in another article.&lt;/p&gt;
  4385. &lt;/div&gt;
  4386. &lt;div class=&quot;paragraph&quot;&gt;
  4387. &lt;p&gt;Extend your &lt;code&gt;shiro.ini&lt;/code&gt; by two sections:&lt;/p&gt;
  4388. &lt;/div&gt;
  4389. &lt;div class=&quot;listingblock&quot;&gt;
  4390. &lt;div class=&quot;title&quot;&gt;A shiro.ini with an admin user&lt;/div&gt;
  4391. &lt;div class=&quot;content&quot;&gt;
  4392. &lt;pre class=&quot;highlightjs highlight&quot;&gt;&lt;code class=&quot;language-ini hljs&quot; data-lang=&quot;ini&quot;&gt;[main]
  4393.  
  4394. [users]
  4395. # format: username = password, role1, role2, ..., roleN
  4396. # root:Start123
  4397. root = &quot;$shiro1$SHA-256$500000$MD1ILiY3dLHYa5n4Ys7FCg==$asN2AWGqceSJgo7AjpzlDgEVC9XB4Q/sbHRG17TTY+4=&quot;,admin
  4398. guest = guest,guest
  4399.  
  4400. [roles]
  4401. # format: roleName = permission1, permission2, ..., permissionN
  4402. admin = *
  4403.  
  4404. [urls]
  4405. /** = noSessionCreation,authcBasic[permissive]&lt;/code&gt;&lt;/pre&gt;
  4406. &lt;/div&gt;
  4407. &lt;/div&gt;
  4408. &lt;div class=&quot;paragraph&quot;&gt;
  4409. &lt;p&gt;Try to curl your endpoint again with the user &apos;root&apos; and the password &apos;Start123&apos; – it is now available.
  4410. This is also the end of this basic tutorial.
  4411. You successfully secured your JAX-RS endpoint!&lt;/p&gt;
  4412. &lt;/div&gt;
  4413. &lt;/div&gt;
  4414. &lt;/div&gt;
  4415. &lt;/div&gt;
  4416. &lt;div class=&quot;sect1&quot;&gt;
  4417. &lt;h2 id=&quot;testing_your_shiro_endpoints&quot;&gt;Testing your Shiro Endpoints&lt;/h2&gt;
  4418. &lt;div class=&quot;sectionbody&quot;&gt;
  4419. &lt;div class=&quot;paragraph&quot;&gt;
  4420. &lt;p&gt;We test our endpoints in the main branch of Shiro which is the Shiro 2 branch.
  4421. You can see our unit tests here:&lt;/p&gt;
  4422. &lt;/div&gt;
  4423. &lt;div class=&quot;ulist&quot;&gt;
  4424. &lt;ul&gt;
  4425. &lt;li&gt;
  4426. &lt;p&gt;Test app sources: &lt;a href=&quot;https://github.com/apache/shiro/tree/main/integration-tests/jaxrs/app&quot; class=&quot;bare&quot;&gt;https://github.com/apache/shiro/tree/main/integration-tests/jaxrs/app&lt;/a&gt;&lt;/p&gt;
  4427. &lt;/li&gt;
  4428. &lt;li&gt;
  4429. &lt;p&gt;Tests to be executed: &lt;a href=&quot;https://github.com/apache/shiro/tree/main/integration-tests/jaxrs/tests&quot; class=&quot;bare&quot;&gt;https://github.com/apache/shiro/tree/main/integration-tests/jaxrs/tests&lt;/a&gt;&lt;/p&gt;
  4430. &lt;/li&gt;
  4431. &lt;li&gt;
  4432. &lt;p&gt;The execution using Open Liberty: &lt;a href=&quot;https://github.com/apache/shiro/tree/main/integration-tests/jaxrs/openliberty&quot; class=&quot;bare&quot;&gt;https://github.com/apache/shiro/tree/main/integration-tests/jaxrs/openliberty&lt;/a&gt;&lt;/p&gt;
  4433. &lt;/li&gt;
  4434. &lt;li&gt;
  4435. &lt;p&gt;The execution using Apache Meecrowave: &lt;a href=&quot;https://github.com/apache/shiro/tree/main/integration-tests/jaxrs/meecrowave&quot; class=&quot;bare&quot;&gt;https://github.com/apache/shiro/tree/main/integration-tests/jaxrs/meecrowave&lt;/a&gt;&lt;/p&gt;
  4436. &lt;/li&gt;
  4437. &lt;/ul&gt;
  4438. &lt;/div&gt;
  4439. &lt;div class=&quot;paragraph&quot;&gt;
  4440. &lt;p&gt;This should give you enough resources on how to start a real application server without Arquillian or Docker (TestContainers).
  4441. The tests are using mostly standards where applicable, e.g. the JAX-RS client for quering the data.
  4442. Apache Johnzon is used for JSON parsing, which is also a valid JSON-B implementation.&lt;/p&gt;
  4443. &lt;/div&gt;
  4444. &lt;/div&gt;
  4445. &lt;/div&gt;
  4446. &lt;div class=&quot;sect1&quot;&gt;
  4447. &lt;h2 id=&quot;conclusions&quot;&gt;Conclusions&lt;/h2&gt;
  4448. &lt;div class=&quot;sectionbody&quot;&gt;
  4449. &lt;div class=&quot;paragraph&quot;&gt;
  4450. &lt;p&gt;In this tutorial you learned what Apache Shiro is and how you can use it to secure your JAX-RS endpoints.
  4451. Apache Shiro allows granular permissions, which are subject to another tutorial.&lt;/p&gt;
  4452. &lt;/div&gt;
  4453. &lt;div class=&quot;paragraph&quot;&gt;
  4454. &lt;p&gt;This simple setup is used as an integration test for Apache Shiro 2 and is therefore a valid real world example.&lt;/p&gt;
  4455. &lt;/div&gt;
  4456. &lt;/div&gt;
  4457. &lt;/div&gt;
  4458. &lt;div class=&quot;sect1&quot;&gt;
  4459. &lt;h2 id=&quot;alternatives_to_apache_shiro&quot;&gt;Alternatives to Apache Shiro&lt;/h2&gt;
  4460. &lt;div class=&quot;sectionbody&quot;&gt;
  4461. &lt;div class=&quot;dlist&quot;&gt;
  4462. &lt;dl&gt;
  4463. &lt;dt class=&quot;hdlist1&quot;&gt;Jakarta EE Security&lt;/dt&gt;
  4464. &lt;dd&gt;
  4465. &lt;p&gt;While Apache Shiro does not implement the Jakarta Security API, you can use it with an implementation like Soteria.
  4466. Soteria however does not allow you to use annotations on your JAX-RS endpoint and only implements roles, but no permissions.
  4467. Use it if you do not want to ship an implementation library to keep your archive small and when you do not need
  4468. fine-grained control over your user’s permissions.&lt;/p&gt;
  4469. &lt;/dd&gt;
  4470. &lt;dt class=&quot;hdlist1&quot;&gt;Spring Security&lt;/dt&gt;
  4471. &lt;dd&gt;
  4472. &lt;p&gt;While &lt;a href=&quot;https://shiro.apache.org/spring-boot.html&quot;&gt;Apache Shiro does integrate with Spring-Boot&lt;/a&gt; and the Spring framework,
  4473. the Spring team put a lot of work into Spring Security.&lt;/p&gt;
  4474. &lt;/dd&gt;
  4475. &lt;/dl&gt;
  4476. &lt;/div&gt;
  4477. &lt;/div&gt;
  4478. &lt;/div&gt;
  4479. &lt;div class=&quot;sect1&quot;&gt;
  4480. &lt;h2 id=&quot;further_reading&quot;&gt;Further reading&lt;/h2&gt;
  4481. &lt;div class=&quot;sectionbody&quot;&gt;
  4482. &lt;div class=&quot;paragraph&quot;&gt;
  4483. &lt;p&gt;There is some documentation you will want to read and which was used to create this tutorial:&lt;/p&gt;
  4484. &lt;/div&gt;
  4485. &lt;div class=&quot;ulist&quot;&gt;
  4486. &lt;ul&gt;
  4487. &lt;li&gt;
  4488. &lt;p&gt;General information about configuring Apache Shiro via &lt;code&gt;shiro.ini&lt;/code&gt; file:&lt;br&gt;
  4489. &lt;a href=&quot;https://shiro.apache.org/configuration.html#Configuration-INIConfiguration&quot; class=&quot;bare&quot;&gt;https://shiro.apache.org/configuration.html#Configuration-INIConfiguration&lt;/a&gt;&lt;/p&gt;
  4490. &lt;/li&gt;
  4491. &lt;li&gt;
  4492. &lt;p&gt;Configuring &lt;code&gt;shiro.ini&lt;/code&gt; for web applications:&lt;br&gt;
  4493. &lt;a href=&quot;https://shiro.apache.org/web.html#web_ini&quot; class=&quot;bare&quot;&gt;https://shiro.apache.org/web.html#web_ini&lt;/a&gt;&lt;/p&gt;
  4494. &lt;/li&gt;
  4495. &lt;li&gt;
  4496. &lt;p&gt;Short introduction to JAX-RS with Apache Shiro:&lt;br&gt;
  4497. &lt;a href=&quot;https://shiro.apache.org/jaxrs.html&quot; class=&quot;bare&quot;&gt;https://shiro.apache.org/jaxrs.html&lt;/a&gt;&lt;/p&gt;
  4498. &lt;/li&gt;
  4499. &lt;/ul&gt;
  4500. &lt;/div&gt;
  4501. &lt;/div&gt;
  4502. &lt;/div&gt;
  4503.    </content>
  4504.  </entry>
  4505.  
  4506.  
  4507. </feed>
  4508.