PageSourceSearch

https://www.hacktotech.net/

html hacktotech.net collected 2026-10-05 05:02:59 UTC 93,424 bytes, 2,164 lines download raw bytes

1<!DOCTYPE html>
2<html
3  lang="ja"
4
5
6data-admin-domain="//blog.hatena.ne.jp"
7data-admin-origin="https://blog.hatena.ne.jp"
8data-author="atr0phy"
9data-avail-langs="ja en"
10data-blog="atr0phy.hateblo.jp"
11data-blog-host="atr0phy.hateblo.jp"
12data-blog-is-public="1"
13data-blog-name="HackToTech"
14data-blog-owner="atr0phy"
15data-blog-show-ads=""
16data-blog-show-sleeping-ads=""
17data-blog-uri="https://www.hacktotech.net/"
18data-blog-uuid="26006613489834982"
19data-blogs-uri-base="https://www.hacktotech.net"
20data-brand="pro"
21data-data-layer="{&quot;hatenablog&quot;:{&quot;admin&quot;:{},&quot;analytics&quot;:{&quot;brand_property_id&quot;:&quot;&quot;,&quot;measurement_id&quot;:&quot;G-N5T771Z5Q2&quot;,&quot;non_sampling_property_id&quot;:&quot;&quot;,&quot;property_id&quot;:&quot;&quot;,&quot;separated_property_id&quot;:&quot;UA-29716941-18&quot;},&quot;blog&quot;:{&quot;blog_id&quot;:&quot;26006613489834982&quot;,&quot;content_seems_japanese&quot;:&quot;true&quot;,&quot;disable_ads&quot;:&quot;custom_domain&quot;,&quot;enable_ads&quot;:&quot;false&quot;,&quot;entry_show_footer_related_entries&quot;:&quot;true&quot;,&quot;force_pc_view&quot;:&quot;true&quot;,&quot;is_public&quot;:&quot;true&quot;,&quot;is_responsive_view&quot;:&quot;true&quot;,&quot;is_sleeping&quot;:&quot;false&quot;,&quot;lang&quot;:&quot;ja&quot;,&quot;name&quot;:&quot;HackToTech&quot;,&quot;owner_name&quot;:&quot;atr0phy&quot;,&quot;uri&quot;:&quot;https://www.hacktotech.net/&quot;},&quot;brand&quot;:&quot;pro&quot;,&quot;page_id&quot;:&quot;index&quot;,&quot;permalink_entry&quot;:null,&quot;pro&quot;:&quot;pro&quot;,&quot;router_type&quot;:&quot;blogs&quot;}}"
22data-device="pc"
23data-dont-recommend-pro="false"
24data-global-domain="https://hatena.blog"
25data-globalheader-color="b"
26data-globalheader-type="pc"
27data-has-touch-view="1"
28data-help-url="https://help.hatenablog.com"
29data-hide-header="1"
30data-no-suggest-touch-view="1"
31data-page="index"
32data-parts-domain="https://hatenablog-parts.com"
33data-plus-available="1"
34data-pro="true"
35data-router-type="blogs"
36data-sentry-dsn="https://[email protected]/1195218"
37data-sentry-environment="production"
38data-sentry-sample-rate="0.1"
39data-static-domain="https://cdn.blog.st-hatena.com"
40data-version="89f69427ebf1344326896140241320"
41
42
43
44
45
46
47  data-initial-state="{}"
48
49  >
50  <head prefix="og: http://ogp.me/ns# fb: http://ogp.me/ns/fb#">
51
52  
53
54  
55  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
56
57
58  
59
60
61  
62
63  <meta name="robots" content="max-image-preview:large" />
64
65
66  <meta charset="utf-8"/>
67  <meta http-equiv="X-UA-Compatible" content="IE=7; IE=9; IE=10; IE=11" />
68  <title>HackToTech</title>
69
70  
71  <link rel="canonical" href="https://www.hacktotech.net/"/>
72
73
74
75  
76
77<meta itemprop="name" content="HackToTech"/>
78
79  <meta itemprop="image" content="https://cdn.user.blog.st-hatena.com/default_entry_og_image/155647406/1577715909980632"/>
80
81
82  <meta property="og:title" content="HackToTech"/>
83<meta property="og:type" content="blog"/>
84  <meta property="og:url" content="https://www.hacktotech.net/"/>
85
86  
87  
88  
89  <meta property="og:image" content="https://cdn.image.st-hatena.com/image/scale/edca2a88f8dc0230ccb85966912813a578c7fd12/backend=imagemagick;enlarge=0;height=1000;version=1;width=1200/https%3A%2F%2Fcdn.user.blog.st-hatena.com%2Fdefault_entry_og_image%2F155647406%2F1577715909980632"/>
90
91<meta property="og:image:alt" content="HackToTech"/>
92  <meta property="og:description" content="Hack To Technology" />
93<meta property="og:site_name" content="HackToTech"/>
94
95      <meta name="twitter:card"  content="summary_large_image" />
96    <meta name="twitter:image" content="https://cdn.user.blog.st-hatena.com/default_entry_og_image/155647406/1577715909980632" />  <meta name="twitter:title" content="HackToTech" />  <meta name="twitter:description" content="Hack To Technology" />  <meta name="twitter:app:name:iphone" content="はてなブログアプリ" />
97  <meta name="twitter:app:id:iphone" content="583299321" />
98  <meta name="twitter:app:url:iphone" content="hatenablog:///open?uri=https%3A%2F%2Fwww.hacktotech.net%2F" />  <meta name="twitter:site" content="@_atr0phy_" />
99  
100    <meta name="google-site-verification" content="7P6tlmARw_v-2DggAkyXs-m7DeLWnThwfj_gURrRfdE" />
101
102
103  
104<script
105  id="embed-gtm-data-layer-loader"
106  data-data-layer-page-specific=""
107>
108(function() {
109  function loadDataLayer(elem, attrName) {
110    if (!elem) { return {}; }
111    var json = elem.getAttribute(attrName);
112    if (!json) { return {}; }
113    return JSON.parse(json);
114  }
115
116  var globalVariables = loadDataLayer(
117    document.documentElement,
118    'data-data-layer'
119  );
120  var pageSpecificVariables = loadDataLayer(
121    document.getElementById('embed-gtm-data-layer-loader'),
122    'data-data-layer-page-specific'
123  );
124
125  var variables = [globalVariables, pageSpecificVariables];
126
127  if (!window.dataLayer) {
128    window.dataLayer = [];
129  }
130
131  for (var i = 0; i < variables.length; i++) {
132    window.dataLayer.push(variables[i]);
133  }
134})();
135</script>
135
136
137<!-- Google Tag Manager -->
138<script>
vendor: 327 bytes, lines 138-142
138(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':
139new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],
140j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=
141'https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f);
142})(window,document,'script','dataLayer','
142GTM-P4CXTW
vendor: 3 bytes, line 142
142');
142</script>
142
143<!-- End Google Tag Manager -->
144
145
146
147
148
149
150
151
152
153
154
155  <link rel="shortcut icon" href="https://www.hacktotech.net/icon/favicon">
156<link rel="apple-touch-icon" href="https://www.hacktotech.net/icon/touch">
157<link rel="icon" sizes="192x192" href="https://www.hacktotech.net/icon/link">
158
159  
160
161<link rel="alternate" type="application/atom+xml" title="Atom" href="https://www.hacktotech.net/feed"/>
162<link rel="alternate" type="application/rss+xml" title="RSS2.0" href="https://www.hacktotech.net/rss"/>
163
164  
165  
166  <link rel="author" href="http://www.hatena.ne.jp/atr0phy/">
167
168
169  
170
171  
172
173
174  
175    
176<link rel="stylesheet" type="text/css" href="https://cdn.blog.st-hatena.com/css/blog.css?version=89f69427ebf1344326896140241320"/>
177
178    
179  <link rel="stylesheet" type="text/css" href="https://usercss.blog.st-hatena.com/blog_style/26006613489834982/7d2fe7769e84a69cf056ba335119ef492f269bbc"/>
180  
181  
182  
183
184  
185
186  
187<script> </script>
187
188
189  
190<style>
191  div#google_afc_user,
192  div.google-afc-user-container,
193  div.google_afc_image,
194  div.google_afc_blocklink {
195      display: block !important;
196  }
197</style>
198
199
200  
201
202  
203    
203<script type="application/ld+json">{"@context":"https://schema.org","@type":"WebSite","name":"HackToTech","url":"https://www.hacktotech.net/"}</script>
vendor: 71 bytes, lines 203-207
203
204
205  
206
207  <script async src="https://www.googletagmanager.com/gtag/js?id=
207G-N5T771Z5Q2
vendor: 12 bytes, line 207
207"></script>
208<script>
209  
vendor: 134 bytes, lines 209-213
209window.dataLayer = window.dataLayer || [];
210  function gtag(){dataLayer.push(arguments);}
211  gtag('js', new Date());
212
213  gtag('config', '
213G-N5T771Z5Q2
vendor: 4 bytes, line 213
213');
214</script>
214
215
216  
217
218</head>
219
220  <body class="page-index globalheader-off globalheader-ng-enabled">
221    
222    
223
224<div id="globalheader-container"
225  data-brand="hatenablog"
226  style="display: none"
227  >
228  <iframe id="globalheader" height="37" frameborder="0" allowTransparency="true"></iframe>
229</div>
230
231
232  
233  
234  
235
236  <div id="container">
237    <div id="container-inner">
238      <header id="blog-title" data-brand="hatenablog">
239  <div id="blog-title-inner" >
240    <div id="blog-title-content">
241      <h1 id="title"><a href="https://www.hacktotech.net/">HackToTech</a></h1>
242      
243        <h2 id="blog-description">Hack To Technology</h2>
244      
245    </div>
246  </div>
247</header>
248
249      
250
251
252      
253      
254
255
256
257
258<div id="content" class="hfeed"
259  
260  >
261  <div id="content-inner">
262    <div id="wrapper">
263      <div id="main">
264        <div id="main-inner">
265          
266
267          
268
269
270
271          
272  
273  <!-- google_ad_section_start -->
274  <!-- rakuten_ad_target_begin -->
275  
276  
277  
278
279  
280
281  
282    
283      
284        <article class="entry hentry test-hentry js-entry-article date-first autopagerize_page_element chars-4800 words-600 mode-markdown entry-odd" id="entry-6801883189121681232" data-keyword-campaign="" data-uuid="6801883189121681232" data-publication-type="entry">
285  <div class="entry-inner">
286    <header class="entry-header">
287  
288    <div class="date entry-date first">
289    <a href="https://www.hacktotech.net/archive/2024/07/13" rel="nofollow">
290      <time datetime="2024-07-13T14:45:39Z" title="2024-07-13T14:45:39Z">
291        <span class="date-year">2024</span><span class="hyphen">-</span><span class="date-month">07</span><span class="hyphen">-</span><span class="date-day">13</span>
292      </time>
293    </a>
294      </div>
295  <h1 class="entry-title">
296  <a href="https://www.hacktotech.net/entry/mockito-kotlin-value-class" class="entry-title-link bookmark">mockito-kotlinでvalue classがサポートされたらしいのでメモ</a>
297</h1>
298
299  
300  
301
302  <div class="entry-categories categories">
303    
304    <a href="https://www.hacktotech.net/archive/category/mockito" class="entry-category-link category-mockito">mockito</a>
305    
306    <a href="https://www.hacktotech.net/archive/category/kotlin" class="entry-category-link category-kotlin">kotlin</a>
307    
308  </div>
309
310
311  
312
313  
314
315</header>
316
317    
318
319
320    <div class="entry-content hatenablog-entry">
321  
322    <p>控えめに言って神
323<iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Fgithub.com%2Fmockito%2Fmockito-kotlin%2Fpull%2F522" title="Added value class support by LarsSven · Pull Request #522 · mockito/mockito-kotlin" class="embed-card embed-webcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 155px; max-width: 500px; margin: 10px 0px;" loading="lazy"></iframe><cite class="hatena-citation"><a href="https://github.com/mockito/mockito-kotlin/pull/522">github.com</a></cite>
3245.4.0のリリースに含まれている
325<iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Fgithub.com%2Fmockito%2Fmockito-kotlin%2Freleases%2Ftag%2F5.4.0" title="Release 5.4.0 · mockito/mockito-kotlin" class="embed-card embed-webcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 155px; max-width: 500px; margin: 10px 0px;" loading="lazy"></iframe><cite class="hatena-citation"><a href="https://github.com/mockito/mockito-kotlin/releases/tag/5.4.0">github.com</a></cite></p>
326
327<h4 id="buildgradlekts">build.gradle.kts</h4>
328
329<pre class="code lang-kotlin" data-lang="kotlin" data-unlink>plugins {
330    kotlin(<span class="synConstant">&quot;jvm&quot;</span>) version <span class="synConstant">&quot;2.0.0&quot;</span>
331}
332
333group = <span class="synConstant">&quot;com.github.atr0phy&quot;</span>
334version = <span class="synConstant">&quot;1.0-SNAPSHOT&quot;</span>
335
336repositories {
337    mavenCentral()
338}
339
340dependencies {
341    testImplementation(kotlin(<span class="synConstant">&quot;test&quot;</span>))
342    testImplementation(<span class="synConstant">&quot;org.mockito.kotlin:mockito-kotlin:5.4.0&quot;</span>)
343}
344
345tasks.test {
346    useJUnitPlatform()
347}
348kotlin {
349    jvmToolchain(<span class="synConstant">17</span>)
350}
351</pre>
352
353
354<h4 id="コード">コード</h4>
355
356<pre class="code lang-kotlin" data-lang="kotlin" data-unlink><span class="synPreProc">
356import</span> org.mockito.Mockito.mockStatic
357<span class="synPreProc">import</span> org.mockito.kotlin.any
358<span class="synPreProc">import</span> kotlin.test.Test
359<span class="synPreProc">import</span> kotlin.test.assertEquals
360
361<span class="synIdentifier">@JvmInline</span>
362<span class="synType">value</span> <span class="synType">class</span> SampleValue(<span class="synType">val</span> value: <span class="synType">String</span>)
363
364<span class="synType">object</span> SampleValueRepository {
365    <span class="synIdentifier">@JvmStatic</span>
366    <span class="synType">fun</span> save(sampleValue: SampleValue): SampleValue {
367        <span class="synStatement">return</span> sampleValue
368    }
369}
370
371<span class="synType">private</span> <span class="synType">class</span> SampleValueRepositoryTest {
372    <span class="synIdentifier">@Test</span>
373    <span class="synType">fun</span> test() {
374        <span class="synComment">// setup</span>
375        <span class="synType">val</span> expected = SampleValue(<span class="synConstant">&quot;mocked&quot;</span>)
376        <span class="synType">val</span> mocked = mockStatic(SampleValueRepository<span class="synStatement">::</span><span class="synType">class</span>.java)
377        mocked.`when`&lt;SampleValue&gt; { SampleValueRepository.save(any()) }.thenReturn(expected)
378        <span class="synComment">// どっちでもいける</span>
379        <span class="synComment">// mocked.`when`&lt;SampleValue&gt; { SampleValueRepository.save(anyValueClass()) }.thenReturn(expected)</span>
380
381        <span class="synComment">// exercise</span>
382        <span class="synType">val</span> <span class="synType">actual</span> = SampleValueRepository.save(SampleValue(<span class="synConstant">&quot;call&quot;</span>))
383
384        <span class="synComment">// verify</span>
385        assertEquals(expected, <span class="synType">actual</span>)
386    }
387}
388</pre>
389
390
391<h4 id="結果">結果</h4>
392
393<h5 id="540">5.4.0</h5>
394
395<pre class="code" data-lang="" data-unlink>&gt; Task :checkKotlinGradlePluginConfigurationErrors SKIPPED
396&gt; Task :compileKotlin NO-SOURCE
397&gt; Task :compileJava NO-SOURCE
398&gt; Task :processResources NO-SOURCE
399&gt; Task :classes UP-TO-DATE
400&gt; Task :processTestResources NO-SOURCE
401&gt; Task :compileTestKotlin
402&gt; Task :compileTestJava NO-SOURCE
403&gt; Task :testClasses UP-TO-DATE
404&gt; Task :test
405BUILD SUCCESSFUL in 3s
4062 actionable tasks: 2 executed
40723:35:44:  &#39;:test --tests &#34;SampleValueTest&#34;&#39; の実行を完了しました。</pre>
408
409
410<h5 id="531">5.3.1</h5>
411
412<pre class="code" data-lang="" data-unlink>&gt; Task :checkKotlinGradlePluginConfigurationErrors SKIPPED
413&gt; Task :compileKotlin NO-SOURCE
414&gt; Task :compileJava NO-SOURCE
415&gt; Task :processResources NO-SOURCE
416&gt; Task :classes UP-TO-DATE
417&gt; Task :processTestResources NO-SOURCE
418&gt; Task :compileTestKotlin
419&gt; Task :compileTestJava NO-SOURCE
420&gt; Task :testClasses UP-TO-DATE
421
422
423Misplaced or misused argument matcher detected here:
424
425-&gt; at SampleValueTest.test$lambda$0(SampleValueTest.kt:32)
426
427You cannot use argument matchers outside of verification or stubbing.
428Examples of correct usage of argument matchers:
429    when(mock.get(anyInt())).thenReturn(null);
430    doThrow(new RuntimeException()).when(mock).someVoidMethod(any());
431    verify(mock).someMethod(contains(&#34;foo&#34;))
432
433This message may appear after an NullPointerException if the last matcher is returning an object 
434like any() but the stubbed method signature expect a primitive argument, in this case,
435use primitive alternatives.
436    when(mock.get(any())); // bad use, will raise NPE
437    when(mock.get(anyInt())); // correct usage use
438
439Also, this error might show up because you use argument matchers with methods that cannot be mocked.
440Following methods *cannot* be stubbed/verified: final/private/equals()/hashCode().
441Mocking methods declared on non-public parent classes is not supported.
442
443org.mockito.exceptions.misusing.InvalidUseOfMatchersException: 
444Misplaced or misused argument matcher detected here:
445
446-&gt; at SampleValueTest.test$lambda$0(SampleValueTest.kt:32)
447
448You cannot use argument matchers outside of verification or stubbing.
449Examples of correct usage of argument matchers:
450    when(mock.get(anyInt())).thenReturn(null);
451    doThrow(new RuntimeException()).when(mock).someVoidMethod(any());
452    verify(mock).someMethod(contains(&#34;foo&#34;))
453
454This message may appear after an NullPointerException if the last matcher is returning an object 
455like any() but the stubbed method signature expect a primitive argument, in this case,
456use primitive alternatives.
457    when(mock.get(any())); // bad use, will raise NPE
458    when(mock.get(anyInt())); // correct usage use
459
460Also, this error might show up because you use argument matchers with methods that cannot be mocked.
461Following methods *cannot* be stubbed/verified: final/private/equals()/hashCode().
462Mocking methods declared on non-public parent classes is not supported.
463
464    at SampleValueTest.test(SampleValueTest.kt:22)
465    at java.base/java.lang.reflect.Method.invoke(Method.java:568)
466    at java.base/java.util.ArrayList.forEach(ArrayList.java:1511)
467    at java.base/java.util.ArrayList.forEach(ArrayList.java:1511)
468
469
470OpenJDK 64-Bit Server VM warning: Sharing is only supported for boot loader classes because bootstrap classpath has been appended
471&gt; Task :test FAILED
472SampleValueTest &gt; test() FAILED
473    org.mockito.exceptions.misusing.InvalidUseOfMatchersException at SampleValueTest.kt:22
4741 test completed, 1 failed
475</pre>
476
477
478<p>公式でサポートされたの嬉しい</p>
479
480    
481    
482    
483  
484</div>
485
486    
487  <footer class="entry-footer">
488    
489    <div class="entry-tags-wrapper">
490  <div class="entry-tags">  </div>
491</div>
492
493    <p class="entry-footer-section track-inview-by-gtm" data-gtm-track-json="{&quot;area&quot;: &quot;finish_reading&quot;}">
494  <span class="author vcard"><span class="fn" data-load-nickname="1" data-user-name="atr0phy" >atr0phy</span></span>
495  <span class="entry-footer-time"><a href="https://www.hacktotech.net/entry/mockito-kotlin-value-class"><time data-relative datetime="2024-07-13T14:45:39Z" title="2024-07-13T14:45:39Z" class="updated">2024-07-13 23:45</time></a></span>
496  
497  
498  
499</p>
500
501    
502  <div
503    class="hatena-star-container"
504    data-hatena-star-container
505    data-hatena-star-url="https://www.hacktotech.net/entry/mockito-kotlin-value-class"
506    data-hatena-star-title="mockito-kotlinでvalue classがサポートされたらしいのでメモ"
507    data-hatena-star-variant="profile-icon"
508    data-hatena-star-profile-url-template="https://blog.hatena.ne.jp/{username}/"
509  ></div>
510
511
512    
513<div class="social-buttons">
514  
515  
516    <div class="social-button-item">
517      <a href="https://b.hatena.ne.jp/entry/s/www.hacktotech.net/entry/mockito-kotlin-value-class" class="hatena-bookmark-button" data-hatena-bookmark-url="https://www.hacktotech.net/entry/mockito-kotlin-value-class" data-hatena-bookmark-layout="vertical-balloon" data-hatena-bookmark-lang="ja" title="この記事をはてなブックマークに追加"><img src="https://b.st-hatena.com/images/entry-button/button-only.gif" alt="この記事をはてなブックマークに追加" width="20" height="20" style="border: none;" /></a>
518    </div>
519  
520  
521  
522    
523    
524    <div class="social-button-item">
525      <a
526          class="entry-share-button entry-share-button-twitter test-share-button-twitter"
527          href="https://x.com/intent/tweet?text=mockito-kotlin%E3%81%A7value+class%E3%81%8C%E3%82%B5%E3%83%9D%E3%83%BC%E3%83%88%E3%81%95%E3%82%8C%E3%81%9F%E3%82%89%E3%81%97%E3%81%84%E3%81%AE%E3%81%A7%E3%83%A1%E3%83%A2+-+HackToTech&amp;url=https%3A%2F%2Fwww.hacktotech.net%2Fentry%2Fmockito-kotlin-value-class"
528          title="X(Twitter)で投稿する"
529        ></a>
530    </div>
531  
532  
533  
534  
535  
536  
537</div>
538
539    
540
541    <div class="customized-footer">
542      
543
544    </div>
545    
546
547  </footer>
548
549  </div>
550</article>
551
552      
553      
554    
555  
556    
557      
558        <article class="entry hentry test-hentry js-entry-article date-first autopagerize_page_element chars-8000 words-800 mode-markdown entry-even" id="entry-6801883189109177200" data-keyword-campaign="" data-uuid="6801883189109177200" data-publication-type="entry">
559  <div class="entry-inner">
560    <header class="entry-header">
561  
562    <div class="date entry-date first">
563    <a href="https://www.hacktotech.net/archive/2024/05/25" rel="nofollow">
564      <time datetime="2024-05-25T12:34:21Z" title="2024-05-25T12:34:21Z">
565        <span class="date-year">2024</span><span class="hyphen">-</span><span class="date-month">05</span><span class="hyphen">-</span><span class="date-day">25</span>
566      </time>
567    </a>
568      </div>
569  <h1 class="entry-title">
570  <a href="https://www.hacktotech.net/entry/sbom-memo" class="entry-title-link bookmark">SBOM周りを見てたのでメモ</a>
571</h1>
572
573  
574  
575
576  <div class="entry-categories categories">
577    
578    <a href="https://www.hacktotech.net/archive/category/SBOM" class="entry-category-link category-SBOM">SBOM</a>
579    
580  </div>
581
582
583  
584
585  
586
587</header>
588
589    
590
591
592    <div class="entry-content hatenablog-entry">
593  
594    <p>Spring Boot 3.3でSBOMがサポートされたと聞いたので、どんなもんなのかを試していたのでメモ<br/>
595(SBOMについて詳しく書いてある記事ではないので、そういった記事が見たい場合はブラウザバック推奨)
596<iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Fspring.io%2Fblog%2F2024%2F05%2F24%2Fsbom-support-in-spring-boot-3-3" title="SBOM support in Spring Boot 3.3" class="embed-card embed-webcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 155px; max-width: 500px; margin: 10px 0px;" loading="lazy"></iframe><cite class="hatena-citation"><a href="https://spring.io/blog/2024/05/24/sbom-support-in-spring-boot-3-3">spring.io</a></cite></p>
597
598<p>SBOMについては経産省の資料を見るのが良さそうだった
599<iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Fwww.meti.go.jp%2Fpress%2F2023%2F07%2F20230728004%2F20230728004.html" title="「ソフトウェア管理に向けたSBOM(Software Bill of Materials)の導入に関する手引」を策定しました (METI/経済産業省)" class="embed-card embed-webcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 155px; max-width: 500px; margin: 10px 0px;" loading="lazy"></iframe><cite class="hatena-citation"><a href="https://www.meti.go.jp/press/2023/07/20230728004/20230728004.html">www.meti.go.jp</a></cite></p>
600
601<p>で、この辺り全く詳しくなくて今回から何がどうサポートされたのã
601‹ãŒå…¨ãã‚ã‹ã‚‰ãªã‹ã£ãŸã®ã§ã€æ‰‹ã‚’動かしながら試していた感じ<br/>
602対象の <code>gradle plugin</code> を入れれば <code>bootJar</code> のタスク実行時に<br/>
603<code>JAR</code> の <code>META-INF/sbom/bom.json</code> ( <code>json</code> かは指定によるはず)にSBOMを埋め込んでくれるという話だった
604<iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Fgithub.com%2FCycloneDX%2Fcyclonedx-gradle-plugin" title="GitHub - CycloneDX/cyclonedx-gradle-plugin: Creates CycloneDX Software Bill of Materials (SBOM) from Gradle projects" class="embed-card embed-webcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 155px; max-width: 500px; margin: 10px 0px;" loading="lazy"></iframe><cite class="hatena-citation"><a href="https://github.com/CycloneDX/cyclonedx-gradle-plugin">github.com</a></cite></p>
605
606<p>あとは <code>spring-boot-starter-actuator</code> 入れて <code>application.properties</code> 設定しておけばactuator経由で公開できるようになっていたが、<br/>
607内部的に見たいだけなら特にAPIで取得できなくても良さそうな気もした</p>
608
609<p>普段は <code>trivy</code> で <code>JAR</code> の入ったコンテナイメージの<a href="https://aquasecurity.github.io/trivy/v0.40/docs/vulnerability/languages/java/">脆弱性スキャン</a>をして併せてチェックしているが、<br/>
610SBOM作ってそっちを <code>trivy</code> か <code>osv-scanner</code> に食わせたほうが良かったりするのか気になる</p>
611
612<h3 id="適当にCVEがあるバージョンのライブラリを使ったアプリケーションでSBOMを作って試して見る">適当にCVEがあるバージョンのライブラリを使ったアプリケーションで、SBOMを作って試して見る</h3>
613
614<p>作ったSBOM(直接埋め込むとかなり長いのでgistへのリンク)
615<a href="https://gist.github.com/atr0phy/0d853f5c251e7e20116d50ae78aabf58#file-sbom-json">https://gist.github.com/atr0phy/0d853f5c251e7e20116d50ae78aabf58#file-sbom-json</a></p>
616
617<h4 id="trivy">trivy</h4>
618
619<pre class="code bash" data-lang="bash" data-unlink>$ trivy sbom bom.32.json
6202024-05-25T20:44:07+09:00   INFO    Vulnerability scanning is enabled
6212024-05-25T20:44:07+09:00   INFO    Detected SBOM format    format=&#34;cyclonedx-json&#34;
6222024-05-25T20:44:07+09:00   WARN    Third-party SBOM may lead to inaccurate vulnerability detection
6232024-05-25T20:44:07+09:00   WARN    Recommend using Trivy to generate SBOMs
624....
625
626Java (jar)
627
628Total: 8 (UNKNOWN: 0, LOW: 0, MEDIUM: 2, HIGH: 5, CRITICAL: 1)
629
630┌────────────────────────────────────────────────┬────────────────┬──────────┬────────┬───────────────────┬─────────────────────────────────────────────────┬──────────────────────────────────────────────────────────────┐
631│                    Library                     │ Vulnerability  │ Severity │ Status │ Installed Version │                  Fixed Version                  │                            Title                             │
632├────────────────────────────────────────────────┼────────────────┼──────────┼────────┼───────────────────┼─────────────────────────────────────────────────┼──────────────────────────────────────────────────────────────┤
633│ ch.qos.logback:logback-classic                 │ CVE-2023-6378  │ HIGH     │ fixed  │ 1.4.11            │ 1.3.12, 1.4.12, 1.2.13                          │ logback: serialization vulnerability in logback receiver     │
634│                                                │                │          │        │                   │                                                 │ https://avd.aquasec.com/nvd/cve-2023-6378                    │
635├────────────────────────────────────────────────┤                │          │        │                   │                                                 │                                                              │
636│ ch.qos.logback:logback-core                    │                │          │        │                   │                                                 │                                                              │
637│                                                │                │          │        │                   │                                                 │                                                              │
638├────────────────────────────────────────────────┼────────────────┼──────────┤        ├───────────────────┼─────────────────────────────────────────────────┼──────────────────────────────────────────────────────────────┤
639│ org.apache.tomcat.embed:tomcat-embed-core      │ CVE-2024-24549 │ MEDIUM   │        │ 10.1.16           │ 8.5.99, 9.0.86, 10.1.19, 11.0.0-M17             │ : Apache Tomcat: HTTP/2 header handling DoS                  │
640│                                                │                │          │        │                   │                                                 │ https://avd.aquasec.com/nvd/cve-2024-24549                   │
641├────────────────────────────────────────────────┼────────────────┤          │        │                   ├─────────────────────────────────────────────────┼──────────────────────────────────────────────────────────────┤
642│ org.apache.tomcat.embed:tomcat-embed-websocket │ CVE-2024-23672 │          │        │                   │ 11.0.0-M17, 10.1.19, 9.0.86, 8.5.99             │ Apache Tomcat: WebSocket DoS with incomplete closing         │
643│                                                │                │          │        │                   │                                                 │ handshake                                                    │
644│                                                │                │          │        │                   │                                                 │ https://avd.aquasec.com/nvd/cve-2024-23672                   │
645├────────────────────────────────────────────────┼────────────────┼──────────┤        ├───────────────────┼─────────────────────────────────────────────────┼──────────────────────────────────────────────────────────────┤
646│ org.postgresql:postgresql                      │ CVE-2024-1597  │ CRITICAL │        │ 42.7.1            │ 42.2.28, 42.3.9, 42.4.4, 42.5.5, 42.6.1, 42.7.2 │ pgjdbc: PostgreSQL JDBC Driver allows attacker to inject SQL │
647│                                                │                │          │        │                   │                                                 │ if using PreferQueryMode=SIMPLE...                           │
648│                                                │                │          │        │                   │                                                 │ https://avd.aquasec.com/nvd/cve-2024-1597                    │
649├────────────────────────────────────────────────┼────────────────┼──────────┤        ├───────────────────┼─────────────────────────────────────────────────┼──────────────────────────────────────────────────────────────┤
650│ org.springframework:spring-web                 │ CVE-2024-22243 │ HIGH     │        │ 6.1.1             │ 6.1.4, 6.0.17, 5.3.32                           │ springframework: URL Parsing with Host Validation            │
651│                                                │                │          │        │                   │                                                 │ https://avd.aquasec.com/nvd/cve-2024-22243                   │
652│                                                ├────────────────┤          │        │                   ├─────────────────────────────────────────────────┼──────────────────────────────────────────────────────────────┤
653│                                                │ CVE-2024-22259 │          │        │                   │ 6.1.5, 6.0.18, 5.3.33                           │ springframework: URL Parsing with Host Validation            │
654│                                                │                │          │        │                   │                                                 │ https://avd.aquasec.com/nvd/cve-2024-22259                   │
655│                                                ├────────────────┤          │        │                   ├─────────────────────────────────────────────────┼──────────────────────────────────────────────────────────────┤
656│                                                │ CVE-2024-22262 │          │        │                   │ 5.3.34, 6.0.19, 6.1.6                           │ springframework: URL Parsing with Host Validation            │
657│                                                │                │          │        │                   │                                                 │ https://avd.aquasec.com/nvd/cve-2024-22262                   │
658└────────────────────────────────────────────────┴────────────────┴──────────┴────────┴───────────────────┴─────────────────────────────────────────────────┴──────────────────────────────────────────────────────────────┘
659</pre>
660
661
662<p>trivyの方が修正バージョンも出ていて親切だが、省略した箇所に↓みたいなHASHのWARNが出てくるのだけ見づらいのでどうにかしたほうが良さそうだった</p>
663
664<pre class="code bash" data-lang="bash" data-unlink>2024-05-25T20:43:52+09:00   WARN    Unsupported hash algorithm  algorithm=&#34;SHA3-384&#34;
6652024-05-25T20:43:52+09:00   WARN    Unsupported hash algorithm  algorithm=&#34;SHA3-256&#34;
6662024-05-25T20:43:52+09:00   WARN    Unsupported hash algorithm  algorithm=&#34;SHA3-512&#34;</pre>
667
668
669<h4 id="osv-scanner">osv-scanner</h4>
670
671<pre class="code bash" data-lang="bash" data-unlink>$ osv-scanner scan --sbom bom.32.json 
672Scanned /home/atr0phy/workspace/spring-boot-33/build/reports/bom.32.json as CycloneDX SBOM and found 40 packages
673╭─────────────────────────────────────┬──────┬───────────┬────────────────────────────────────────────────┬─────────┬─────────────╮ ≈
674│ OSV URL                             │ CVSS │ ECOSYSTEM │ PACKAGE                                        │ VERSION │ SOURCE      │
675├─────────────────────────────────────┼──────┼───────────┼────────────────────────────────────────────────┼─────────┼─────────────┤ ≈
676│ https://osv.dev/GHSA-24rp-q3w6-vc56 │ 10.0 │ Maven     │ org.postgresql:postgresql                      │ 42.7.1  │ bom.32.json │
677│ https://osv.dev/GHSA-vmq6-5m68-f53m │ 7.1  │ Maven     │ ch.qos.logback:logback-core                    │ 1.4.11  │ bom.32.json │
678│ https://osv.dev/GHSA-7w75-32cg-r6g2 │      │ Maven     │ org.apache.tomcat.embed:tomcat-embed-core      │ 10.1.16 │ bom.32.json │
679│ https://osv.dev/GHSA-2wrp-6fg6-hmc5 │ 8.1  │ Maven     │ org.springframework:spring-web                 │ 6.1.1   │ bom.32.json │
680│ https://osv.dev/GHSA-ccgv-vj62-xf9h │ 8.1  │ Maven     │ org.springframework:spring-web                 │ 6.1.1   │ bom.32.json │
681│ https://osv.dev/GHSA-hgjh-9rj2-g67j │ 8.1  │ Maven     │ org.springframework:spring-web                 │ 6.1.1   │ bom.32.json │
682│ https://osv.dev/GHSA-v682-8vv8-vpwr │      │ Maven     │ org.apache.tomcat.embed:tomcat-embed-websocket │ 10.1.16 │ bom.32.json │
683│ https://osv.dev/GHSA-vmq6-5m68-f53m │ 7.1  │ Maven     │ ch.qos.logback:logback-classic                 │ 1.4.11  │ bom.32.json │
684╰─────────────────────────────────────┴──────┴───────────┴────────────────────────────────────────────────┴─────────┴─────────────╯ ≈</pre>
685
686
687<h3 id="試していた-buildgradlekts">試していた <code>build.gradle.kts</code></h3>
688
689<p>上記の
689SBOM生成時は、複数の脆弱性が見たかったので <code>id("org.springframework.boot") version "3.2.0"</code> を使用した</p>
690
691<pre class="code lang-kotlin" data-lang="kotlin" data-unlink><span class="synPreProc">import</span> org.jetbrains.kotlin.gradle.tasks.KotlinCompile
692
693plugins {
694    id(<span class="synConstant">&quot;org.springframework.boot&quot;</span>) version <span class="synConstant">&quot;3.3.0&quot;</span>
695    id(<span class="synConstant">&quot;io.spring.dependency-management&quot;</span>) version <span class="synConstant">&quot;1.1.5&quot;</span>
696    kotlin(<span class="synConstant">&quot;jvm&quot;</span>) version <span class="synConstant">&quot;1.9.24&quot;</span>
697    kotlin(<span class="synConstant">&quot;plugin.spring&quot;</span>) version <span class="synConstant">&quot;1.9.24&quot;</span>
698    id(<span class="synConstant">&quot;org.cyclonedx.bom&quot;</span>) version <span class="synConstant">&quot;1.8.2&quot;</span>
699}
700
701group = <span class="synConstant">&quot;com.github.atr0phy&quot;</span>
702version = <span class="synConstant">&quot;0.0.1-SNAPSHOT&quot;</span>
703
704java {
705    sourceCompatibility = JavaVersion.VERSION_17
706}
707
708repositories {
709    mavenCentral()
710}
711
712dependencies {
713    implementation(<span class="synConstant">&quot;org.springframework.boot:spring-boot-starter-web&quot;</span>)
714    <span class="synComment">// implementation(&quot;org.springframework.boot:spring-boot-starter-actuator&quot;)</span>
715    implementation(<span class="synConstant">&quot;com.fasterxml.jackson.module:jackson-module-kotlin&quot;</span>)
716    implementation(<span class="synConstant">&quot;org.jetbrains.kotlin:kotlin-reflect&quot;</span>)
717    <span class="synComment">// わざとCVEの含まれるバージョンを入れる</span>
718    implementation(<span class="synConstant">&quot;org.postgresql:postgresql:42.7.1&quot;</span>)
719    testImplementation(<span class="synConstant">&quot;org.springframework.boot:spring-boot-starter-test&quot;</span>)
720    testRuntimeOnly(<span class="synConstant">&quot;org.junit.platform:junit-platform-launcher&quot;</span>)
721}
722
723tasks.withType&lt;KotlinCompile&gt; {
724    kotlinOptions {
725        freeCompilerArgs <span class="synStatement">+</span>= <span class="synConstant">&quot;-Xjsr305=strict&quot;</span>
726        jvmTarget = <span class="synConstant">&quot;17&quot;</span>
727    }
728}
729
730tasks.withType&lt;Test&gt; {
731    useJUnitPlatform()
732}
733
734tasks.cyclonedxBom {
735    <span class="synComment">// ほぼ公式のサンプル通り</span>
736    setIncludeConfigs(listOf(<span class="synConstant">&quot;runtimeClasspath&quot;</span>))
737    setSkipConfigs(listOf(<span class="synConstant">&quot;compileClasspath&quot;</span>, <span class="synConstant">&quot;testCompileClasspath&quot;</span>))
738    setProjectType(<span class="synConstant">&quot;application&quot;</span>)
739    setSchemaVersion(<span class="synConstant">&quot;1.5&quot;</span>)
740    setOutputName(<span class="synConstant">&quot;bom&quot;</span>)
741    setOutputFormat(<span class="synConstant">&quot;json&quot;</span>)
742    setIncludeBomSerialNumber(<span class="synConstant">true</span>)
743    setIncludeLicenseText(<span class="synConstant">true</span>)
744    setComponentVersion(<span class="synConstant">&quot;2.0.0&quot;</span>)
745}
746</pre>
747
748
749    
750    
751    
752  
753</div>
754
755    
756  <footer class="entry-footer">
757    
758    <div class="entry-tags-wrapper">
759  <div class="entry-tags">  </div>
760</div>
761
762    <p class="entry-footer-section track-inview-by-gtm" data-gtm-track-json="{&quot;area&quot;: &quot;finish_reading&quot;}">
763  <span class="author vcard"><span class="fn" data-load-nickname="1" data-user-name="atr0phy" >atr0phy</span></span>
764  <span class="entry-footer-time"><a href="https://www.hacktotech.net/entry/sbom-memo"><time data-relative datetime="2024-05-25T12:34:21Z" title="2024-05-25T12:34:21Z" class="updated">2024-05-25 21:34</time></a></span>
765  
766  
767  
768</p>
769
770    
771  <div
772    class="hatena-star-container"
773    data-hatena-star-container
774    data-hatena-star-url="https://www.hacktotech.net/entry/sbom-memo"
775    data-hatena-star-title="SBOM周りを見てたのでメモ"
776    data-hatena-star-variant="profile-icon"
777    data-hatena-star-profile-url-template="https://blog.hatena.ne.jp/{username}/"
778  ></div>
779
780
781    
782<div class="social-buttons">
783  
784  
785    <div class="social-button-item">
786      <a href="https://b.hatena.ne.jp/entry/s/www.hacktotech.net/entry/sbom-memo" class="hatena-bookmark-button" data-hatena-bookmark-url="https://www.hacktotech.net/entry/sbom-memo" data-hatena-bookmark-layout="vertical-balloon" data-hatena-bookmark-lang="ja" title="この記事をはてなブックマークに追加"><img src="https://b.st-hatena.com/images/entry-button/button-only.gif" alt="この記事をはてなブックマークに追加" width="20" height="20" style="border: none;" /></a>
787    </div>
788  
789  
790  
791    
792    
793    <div class="social-button-item">
794      <a
795          class="entry-share-button entry-share-button-twitter test-share-button-twitter"
796          href="https://x.com/intent/tweet?text=SBOM%E5%91%A8%E3%82%8A%E3%82%92%E8%A6%8B%E3%81%A6%E3%81%9F%E3%81%AE%E3%81%A7%E3%83%A1%E3%83%A2+-+HackToTech&amp;url=https%3A%2F%2Fwww.hacktotech.net%2Fentry%2Fsbom-memo"
797          title="X(Twitter)で投稿する"
798        ></a>
799    </div>
800  
801  
802  
803  
804  
805  
806</div>
807
808    
809
810    <div class="customized-footer">
811      
812
813    </div>
814    
815
816  </footer>
817
818  </div>
819</article>
820
821      
822      
823    
824  
825    
826      
827        <article class="entry hentry test-hentry js-entry-article date-first autopagerize_page_element chars-1200 words-100 mode-markdown entry-odd" id="entry-6801883189102630983" data-keyword-campaign="" data-uuid="6801883189102630983" data-publication-type="entry">
828  <div class="entry-inner">
829    <header class="entry-header">
830  
831    <div class="date entry-date first">
832    <a href="https://www.hacktotech.net/archive/2024/04/30" rel="nofollow">
833      <time datetime="2024-04-30T10:07:50Z" title="2024-04-30T10:07:50Z">
834        <span class="date-year">2024</span><span class="hyphen">-</span><span class="date-month">04</span><span class="hyphen">-</span><span class="date-day">30</span>
835      </time>
836    </a>
837      </div>
838  <h1 class="entry-title">
839  <a href="https://www.hacktotech.net/entry/use-spring-milestone-version" class="entry-title-link bookmark">Springのmilestoneのバージョンを試してたのでメモ</a>
840</h1>
841
842  
843  
844
845  <div class="entry-categories categories">
846    
847    <a href="https://www.hacktotech.net/archive/category/spring" class="entry-category-link category-spring">spring</a>
848    
849  </div>
850
851
852  
853
854  
855
856</header>
857
858    
859
860
861    <div class="entry-content hatenablog-entry">
862  
863    <p>個人的な備忘録<br/>
864<code>6.2.0-M1</code> の新機能の <code>@Fallback</code> 試したかったが、<br/>
865そもそもどこにライブラリが上がっているのかを知らなかったのでメモ
866<iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Fgithub.com%2Fspring-projects%2Fspring-framework%2Freleases%2Ftag%2Fv6.2.0-M1" title="Release v6.2.0-M1 · spring-projects/spring-framework" class="embed-card embed-webcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 155px; max-width: 500px; margin: 10px 0px;" loading="lazy"></iframe><cite class="hatena-citation"><a href="https://github.com/spring-projects/spring-framework/releases/tag/v6.2.0-M1">github.com</a></cite></p>
867
868<p>普通に↓に記載されたリポジトリにあがっているので、
869<iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Fgithub.com%2Fspring-projects%2Fspring-framework%2Fwiki%2FSpring-Framework-Artifacts%23spring-repositories" title="Spring Framework Artifacts" class="embed-card embed-webcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 155px; max-width: 500px; margin: 10px 0px;" loading="lazy"></iframe><cite class="hatena-citation"><a href="https://github.com/spring-projects/spring-framework/wiki/Spring-Framework-Artifacts#spring-repositories">github.com</a></cite></p>
870
871<p>あとはいつも通り <code>build.gradle.kts</code> に記載すれば良い</p>
872
873<pre class="code lang-kotlin" data-lang="kotlin" data-unlink>repositories {
874    mavenCentral()
875    maven {
876        url = uri(<span class="synConstant">&quot;https://repo.spring.io/milestone&quot;</span>)
877    }
878}
879
880dependencies {
881    implementation(<span class="synConstant">&quot;org.springframework.boot:spring-boot-starter&quot;</span>)
882    implementation(<span class="synConstant">&quot;org.springframework.boot:spring-boot-starter-web&quot;</span>)
883    implementation(<span class="synConstant">&quot;org.jetbrains.kotlin:kotlin-reflect&quot;</span>)
884    implementation(<span class="synConstant">&quot;org.springframework:spring-aop:6.2.0-M1&quot;</span>)
885    implementation(<span class="synConstant">&quot;org.springframework:spring-beans:6.2.0-M1&quot;</span>)
886    implementation(<span class="synConstant">&quot;org.springframework:spring-expression:6.2.0-M1&quot;</span>)
887    implementation(<span class="synConstant">&quot;org.springframework:spring-context:6.2.0-M1&quot;</span>)
888    implementation(<span class="synConstant">&quot;org.springframework:spring-core:6.2.0-M1&quot;</span>)
889    implementation(<span class="synConstant">&quot;org.springframework:spring-jcl:6.2.0-M1&quot;</span>)
890    testImplementation(<span class="synConstant">&quot;org.springframework.boot:spring-boot-starter-test&quot;</span>)
891}
892</pre>
893
894
895    
896    
897    
898  
899</div>
900
901    
902  <footer class="entry-footer">
903    
904    <div class="entry-tags-wrapper">
905  <div class="entry-tags">  </div>
906</div>
907
908    <p class="entry-footer-section track-inview-by-gtm" data-gtm-track-json="{&quot;area&quot;: &quot;finish_reading&quot;}">
909  <span class="author vcard"><span class="fn" data-load-nickname="1" data-user-name="atr0phy" >atr0phy</span></span>
910  <span class="entry-footer-time"><a href="https://www.hacktotech.net/entry/use-spring-milestone-version"><time data-relative datetime="2024-04-30T10:07:50Z" title="2024-04-30T10:07:50Z" class="updated">2024-04-30 19:07</time></a></span>
911  
912  
913  
914</p>
915
916    
917  <div
918    class="hatena-star-container"
919    data-hatena-star-container
920    data-hatena-star-url="https://www.hacktotech.net/entry/use-spring-milestone-version"
921    data-hatena-star-title="Springのmilestoneのバージョンを試してたのでメモ"
922    data-hatena-star-variant="profile-icon"
923    data-hatena-star-profile-url-template="https://blog.hatena.ne.jp/{username}/"
924  ></div>
925
926
927    
928<div class="social-buttons">
929  
930  
931    <div class="social-button-item">
932      <a href="https://b.hatena.ne.jp/entry/s/www.hacktotech.net/entry/use-spring-milestone-version" class="hatena-bookmark-button" data-hatena-bookmark-url="https://www.hacktotech.net/entry/use-spring-milestone-version" data-hatena-bookmark-layout="vertical-balloon" data-hatena-bookmark-lang="ja" title="この記事をはてなブックマークに追加"><img src="https://b.st-hatena.com/images/entry-button/button-only.gif" alt="この記事をはてなブックマークに追加" width="20" height="20" style="border: none;" /></a>
933    </div>
934  
935  
936  
937    
938    
939    <div class="social-button-item">
940      <a
941          class="entry-share-button entry-share-button-twitter test-share-button-twitter"
942          href="https://x.com/intent/tweet?text=Spring%E3%81%AEmilestone%E3%81%AE%E3%83%90%E3%83%BC%E3%82%B8%E3%83%A7%E3%83%B3%E3%82%92%E8%A9%A6%E3%81%97%E3%81%A6%E3%81%9F%E3%81%AE%E3%81%A7%E3%83%A1%E3%83%A2+-+HackToTech&amp;url=https%3A%2F%2Fwww.hacktotech.net%2Fentry%2Fuse-spring-milestone-version"
943          title="X(Twitter)で投稿する"
944        ></a>
945    </div>
946  
947  
948  
949  
950  
951  
952</div>
953
954    
955
956    <div class="customized-footer">
957      
958
959    </div>
960    
961
962  </footer>
963
964  </div>
965</article>
966
967      
968      
969    
970  
971    
972      
973        <article class="entry hentry test-hentry js-entry-article date-first autopagerize_page_element chars-2800 words-400 mode-markdown entry-even" id="entry-6801883189095011317" data-keyword-campaign="" data-uuid="6801883189095011317" data-publication-type="entry">
974  <div class="entry-inner">
975    <header class="entry-header">
976  
977    <div class="date entry-date first">
978    <a href="https://www.hacktotech.net/archive/2024/03/31" rel="nofollow">
979      <time datetime="2024-03-31T08:55:26Z" title="2024-03-31T08:55:26Z">
980        <span class="date-year">2024</span><span class="hyphen">-</span><span class="date-month">03</span><span class="hyphen">-</span><span class="date-day">31</span>
981      </time>
982    </a>
983      </div>
984  <h1 class="entry-title">
985  <a href="https://www.hacktotech.net/entry/spring-boot-exception-translator-for-repository-annotation" class="entry-title-link bookmark">SpringBootで@Repositoryがついたクラスのメソッドから投げられた例外を変換して投げ直す</a>
986</h1>
987
988  
989  
990
991  <div class="entry-categories categories">
992    
993    <a href="https://www.hacktotech.net/archive/category/spring-boot" class="entry-category-link category-spring-boot">spring-boot</a>
994    
995    <a href="https://www.hacktotech.net/archive/category/kotlin" class="entry-category-link category-kotlin">kotlin</a>
996    
997  </div>
998
999
1000  
1001
1002  
1003
1004</header>
1005
1006    
1007
1008
1009    <div class="entry-content hatenablog-entry">
1010  
1011    <p>個人的な備忘録</p>
1012
1013<p>レイヤードアーキテクチャでアプリケーションを作っていて、<br/>
1014賛否両論あると思うがドメイン層のバリデーションを作成時とDBからの再構成時にチェックしていて、<br/>
1015作成時は例外をそのまま投げたいが、再構成時はそうしたくないと思っていたので、表題のようなことをしたかった<br/>
1016(変なデータが入ったりしなければこんなことをしなくても良いが、特殊なケースで起こったりする為、モヤモヤしていたので調べていた)</p>
1017
1018<p>例えば、↓みたいなクラスをドメインとして持っていて、 <code>init</code> でバリデーションを行っているとする<br/>
1019バリデーションに失敗した場合は、 <code>DomainException</code> をスローする</p>
1020
1021<pre class="code lang-kotlin" data-lang="kotlin" data-unlink><span class="synType">data</span> <span class="synType">class</span> UserId(<span class="synType">val</span> value: UUID) {
1022    <span class="synType">companion</span> <span class="synType">object</span> {
1023        <span class="synType">fun</span> generate(): UserId {
1024            <span class="synStatement">return</span> UserId(UUID.randomUUID())
1025        }
1026    }
1027}
1028
1029<span class="synType">data</span> <span class="synType">class</span> User(
1030    <span class="synType">val</span> id: UserId,
1031    <span class="synType">val</span> name: UserName,
1032) {
1033    <span class="synType">companion</span> <span class="synType">object</span> {
1034        <span class="synType">fun</span> of(
1035            name: UserName,
1036        ): User {
1037            <span class="synStatement">return</span> User(
1038                id = UserId.generate(),
1039                name = name,
1040            )
1041        }
1042    }
1043}
1044
1045<span class="synType">data</span> <span class="synType">class</span> UserName(<span class="synType">val</span> value: <span class="synType">String</span>) {
1046    <span class="synType">companion</span> <span class="synType">object</span> {
1047        <span class="synType">private</span> <span class="synType">const</span> <span class="synType">val</span> MIN_LENGTH = <span class="synConstant">1</span>
1048        <span class="synType">private</span> <span class="synType">const</span> <span class="synType">val</span> MAX_LENGTH = <span class="synConstant">256</span>
1049
1050        <span class="synType">fun</span> of(value: <span class="synType">String</span>): UserName {
1051            <span class="synStatement">return</span> UserName(value)
1052        }
1053    }
1054
1055    <span class="synType">init</span> {
1056        <span class="synStatement">if</span> (MIN_LENGTH<span class="synStatement"> &gt;</span> value.length <span class="synStatement">||</span>
1057            MAX_LENGTH <span class="synStatement">&lt; </span>value.length) {
1058            <span class="synStatement">throw</span> DomainException(
1059                message = <span class="synConstant">&quot;ユーザ名は</span><span class="synIdentifier">${</span>MIN_LENGTH<span class="synIdentifier">}</span><span class="synConstant">以上</span><span class="synIdentifier">${</span>MAX_LENGTH<span class="synIdentifier">}</span><span class="synConstant">以下の長さである必要があります&quot;</span>,
1060            )
1061        }
1062    }
1063}
1064</pre>
1065
1066
1067<p>リポジトリのインターフェースはとりあえず保存とID検索だけ用意する</p>
1068
1069<pre class="code lang-kotlin" data-lang="kotlin" data-unlink><span class="synType">interface</span> UserRepository {
1070    <span class="synType">fun</span> findById(id: UserId): User
1071    <span class="synType">fun</span> save(user: User)
1072}
1073</pre>
1074
1075
1076<p>実装は以下</p>
1077
1078<pre class="code lang-kotlin" data-lang="kotlin" data-unlink><span class="synIdentifier">@Repository</span>
1079<span class="synType">class</span> UserRepositoryImpl: UserRepository {
1080    <span class="synType">private</span> <span class="synType">val</span> user1 = UserEntity(
1081        id = UUID.fromString(<span class="synConstant">&quot;a687b0bc-0887-483c-8851-4604657162c1&quot;</span>),
1082        name = <span class="synConstant">&quot;&quot;</span>, <span class="synComment">// なんかしらの理由で元々入っていたとする</span>
1083    )
1084
1085    <span class="synType">private</span> <span class="synType">val</span> user2 = UserEntity(
1086        id = UUID.fromString(<span class="synConstant">&quot;bb1304ea-8d78-4b99-b4d1-ce4000c1c9ab&quot;</span>),
1087        name = <span class="synConstant">&quot;テストユーザ&quot;</span>,
1088    )
1089
1090    <span class="synType">private</span> <span class="synType">val</span> map = ConcurrentHashMap(
1091        mapOf(
1092            <span class="synType">Pair</span>(
1093                user1.id,
1094                user1,
1095            ),
1096            <span class="synType">Pair</span>(
1097                user2.id,
1098                user2,
1099            ),
1100        )
1101    )
1102    <span class="synType">override</span> <span class="synType">fun</span> findById(id: UserId): User {
1103        <span class="synStatement">return</span> map.getOrElse(id.value) { <span class="synStatement">throw</span> <span class="synType">RuntimeException</span>(<span class="synConstant">&quot;ユーザが存在しません&quot;</span>) }
1104            .toUser()
1105    }
1106
1107    <span class="synType">override</span> <span class="synType">fun</span> save(user: User) {
1108        <span class="synType">val</span> entity = UserEntity(
1109            id = user.id.value,
1110            name = user.name.value(),
1111        )
1112
1113        <span class="synStatement">if</span>(map.putIfAbsent(user.id.value, entity) <span class="synStatement">!=</span> <span class="synConstant">null</span>) {
1114            <span class="synStatement">throw</span> <span class="synType">RuntimeException</span>(<span class="synConstant">&quot;ユーザがすでに存在します&quot;</span>)
1115        }
1116    }
1117}
1118</pre>
1119
1120
1121<p>今回はDBを使ってないが、DBを使った場合を想定して、DB用のモデルを用意する<br/>
1122ここでDBのモデルからドメインモデルの変換をするが、バリデーションに失敗した場合は <code>DomainException</code> がスローされる</p>
1123
1124<pre class="code lang-kotlin" data-lang="kotlin" data-unlink><span class="synType">data</span> <span class="synType">class</span> UserEntity (
1125    <span class="synType">val</span> id: UUID,
1126    <span class="synType">val</span> name: <span class="synType">String</span>,
1127) {
1128    <span class="synType">fun</span> toUser(): User {
1129        <span class="synStatement">return</span> User(
1130            id = UserId(value = id),
1131            name = UserName(value = name),
1132        )
1133    }
1134}
1135</pre>
1136
1137
1138<p>モデルの変換をするのは <code>@Repository</code> のアノテーションがついたクラスなので、<br/>
1139<a href="https://spring.pleiades.io/spring-framework/reference/core/aop/ataspectj/pointcuts.html#aop-pointcuts-designators">AOP</a>を使って <code>@Repository</code> 内のメソッドで <code>DomainException</code> が投げられたら <code>DomainMappingException</code> に変換して投げ直すことにした<br/>
1140あとはそれぞれの例外に応じて、例外ハンドラーを設定すればいい感じに作成時と再構成時で振る舞いを変えられる</p>
1141
1142<pre class="code lang-kotlin" data-lang="kotlin" data-unlink><span class="synIdentifier">@Aspect</span>
1143<span class="synIdentifier">@Component</span>
1144<span class="synType">class</span> RepositoryExceptionTranslator {
1145    <span class="synIdentifier">@AfterThrowing</span>(value = <span class="synConstant">&quot;@within(org.springframework.stereotype.Repository)&quot;</span>, throwing = <span class="synConstant">&quot;e&quot;</span>)
1146    <span class="synType">fun</span> translate(e: <span class="synType">Throwable</span>) {
1147        <span class="synStatement">throw</span> <span class="synStatement">when</span>(e) {
1148            <span class="synStatement">is</span> DomainException <span class="synType">-&gt;</span> DomainMappingException(e)
1149            <span class="synStatement">else</span> <span class="synType">-&gt;</span> e
1150        }
1151    }
1152}
1153</pre>
1154
1155
1156<p>こういうときはやっぱりAOPが便利だなといった感想<br/>
1157試していたソースのコードは↓</p>
1158
1159<p><iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Fgithub.com%2Fatr0phy%2Fspring-aop-exception-translator" title="GitHub - atr0phy/spring-aop-exception-translator" class="embed-card embed-webcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 155px; max-width: 500px; margin: 10px 0px;" loading="lazy"></iframe><cite class="hatena-citation"><a href="https://github.com/atr0phy/spring-aop-exception-translator">github.com</a></cite></p>
1160
1161    
1162    
1163    
1164  
1165</div>
1166
1167    
1168  <footer class="entry-footer">
1169    
1170    <div class="entry-tags-wrapper">
1171  <div class="entry-tags">  </div>
1172</div>
1173
1174    <p class="entry-footer-section track-inview-by-gtm" data-gtm-track-json="{&quot;area&quot;: &quot;finish_reading&quot;}">
1175  <span class="author vcard"><span class="fn" data-load-nickname="1" data-user-name="atr0phy" >atr0phy</span></span>
1176  <span class="entry-footer-time"><a href="https://www.hacktotech.net/entry/spring-boot-exception-translator-for-repository-annotation"><time data-relative datetime="2024-03-31T08:55:26Z" title="2024-03-31T08:55:26Z" class="updated">2024-03-31 17:55</time></a></span>
1177  
1178  
1179  
1180</p>
1181
1182    
1183  <div
1184    class="hatena-star-container"
1185    data-hatena-star-container
1186    data-hatena-star-url="https://www.hacktotech.net/entry/spring-boot-exception-translator-for-repository-annotation"
1187    data-hatena-star-title="SpringBootで@Repositoryがついたクラスのメソッドから投げられた例外を変換して投げ直す"
1188    data-hatena-star-variant="profile-icon"
1189    data-hatena-star-profile-url-template="https://blog.hatena.ne.jp/{username}/"
1190  ></div>
1191
1192
1193    
1194<div class="social-buttons">
1195  
1196  
1197    <div class="social-button-item">
1198      <a href="https://b.hatena.ne.jp/entry/s/www.hacktotech.net/entry/spring-boot-exception-translator-for-repository-annotation" class="hatena-bookmark-button" data-hatena-bookmark-url="https://www.hacktotech.net/entry/spring-boot-exception-translator-for-repository-annotation" data-hatena-bookmark-layout="vertical-balloon" data-hatena-bookmark-lang="ja" title="この記事をはてなブックマークに追加"><img src="https://b.st-hatena.com/images/entry-button/button-only.gif" alt="この記事をはてなブックマークに追加" width="20" height="20" style="border: none;" /></a>
1199    </div>
1200  
1201  
1202  
1203    
1204    
1205    <div class="social-button-item">
1206      <a
1207          class="entry-share-button entry-share-button-twitter test-share-button-twitter"
1208          href="https://x.com/intent/tweet?text=SpringBoot%E3%81%A7%40Repository%E3%81%8C%E3%81%A4%E3%81%84%E3%81%9F%E3%82%AF%E3%83%A9%E3%82%B9%E3%81%AE%E3%83%A1%E3%82%BD%E3%83%83%E3%83%89%E3%81%8B%E3%82%89%E6%8A%95%E3%81%92%E3%82%89%E3%82%8C%E3%81%9F%E4%BE%8B%E5%A4%96%E3%82%92%E5%A4%89%E6%8F%9B%E3%81%97%E3%81%A6%E6%8A%95%E3%81%92%E7%9B%B4%E3%81%99+-+HackToTech&amp;url=https%3A%2F%2Fwww.hacktotech.net%2Fentry%2Fspring-boot-exception-translator-for-repository-annotation"
1209          title="X(Twitter)で投稿する"
1210        ></a>
1211    </div>
1212  
1213  
1214  
1215  
1216  
1217  
1218</div>
1219
1220    
1221
1222    <div class="customized-footer">
1223      
1224
1225    </div>
1226    
1227
1228  </footer>
1229
1230  </div>
1231</article>
1232
1233      
1234      
1235    
1236  
1237    
1238      
1239        <article class="entry hentry test-hentry js-entry-article date-first autopagerize_page_element chars-200 words-100 mode-markdown entry-odd" id="entry-6801883189078533680" data-keyword-campaign="" data-uuid="6801883189078533680" data-publication-type="entry">
1240  <div class="entry-inner">
1241    <header class="entry-header">
1242  
1243    <div class="date entry-date first">
1244    <a href="https://www.hacktotech.net/archive/2024/01/28" rel="nofollow">
1245      <time datetime="2024-01-27T15:24:48Z" title="2024-01-27T15:24:48Z">
1246        <span class="date-year">2024</span><span class="hyphen">-</span><span class="date-month">01</span><span class="hyphen">-</span><span class="date-day">28</span>
1247      </time>
1248    </a>
1249      </div>
1250  <h1 class="entry-title">
1251  <a href="https://www.hacktotech.net/entry/select-file-by-whiptail-and-ls" class="entry-title-link bookmark">whiptailでlsしてファイル選択した結果を取得する</a>
1252</h1>
1253
1254  
1255  
1256
1257  <div class="entry-categories categories">
1258    
1259    <a href="https://www.hacktotech.net/archive/category/whiptail" class="entry-category-link category-whiptail">whiptail</a>
1260    
1261    <a href="https://www.hacktotech.net/archive/category/bash" class="entry-category-link category-bash">bash</a>
1262    
1263  </div>
1264
1265
1266  
1267
1268  
1269
1270</header>
1271
1272    
1273
1274
1275    <div class="entry-content hatenablog-entry">
1276  
1277    <p>スクリプト書いてるとたまーに欲しくなるやつ<br/>
1278検索してもなんかぱっといい感じのやつが出てこないので(長すぎてコピペするのに躊躇うやつとか)、主に自分のローカルで使うように書いた</p>
1279
1280<script src="https://gist.github.com/atr0phy/a17fead8c0a893ba7ce435da1859a998.js"></script>
1280
1281
1282
1283<p>↓は <code>/sbin</code> で試したやつ
1284<span itemscope itemtype="http://schema.org/Photograph"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/a/atr0phy/20240128/20240128001355.png" width="1200" height="584" loading="lazy" title="" class="hatena-fotolife" itemprop="image"></span>
1285<span itemscope itemtype="http://schema.org/Photograph"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/a/atr0phy/20240128/20240128001406.png" width="455" height="67" loading="lazy" title="" class="hatena-fotolife" itemprop="image"></span></p>
1286
1287<p>macで使うなら <a href="https://formulae.brew.sh/formula/coreutils"><code>brew install coreutils</code> </a>して、 <code>gls</code> 使わないと動かないので注意</p>
1288
1289<p>相変わらず <code>bash</code> 使ってるけど、いい加減他のシェルにしたほうが良いか悩ましい</p>
1290
1291    
1292    
1293    
1294  
1295</div>
1296
1297    
1298  <footer class="entry-footer">
1299    
1300    <div class="entry-tags-wrapper">
1301  <div class="entry-tags">  </div>
1302</div>
1303
1304    <p class="entry-footer-section track-inview-by-gtm" data-gtm-track-json="{&quot;area&quot;: &quot;finish_reading&quot;}">
1305  <span class="author vcard"><span class="fn" data-load-nickname="1" data-user-name="atr0phy" >atr0phy</span></span>
1306  <span class="entry-footer-time"><a href="https://www.hacktotech.net/entry/select-file-by-whiptail-and-ls"><time data-relative datetime="2024-01-27T15:24:48Z" title="2024-01-27T15:24:48Z" class="updated">2024-01-28 00:24</time></a></span>
1307  
1308  
1309  
1310</p>
1311
1312    
1313  <div
1314    class="hatena-star-container"
1315    data-hatena-star-container
1316    data-hatena-star-url="https://www.hacktotech.net/entry/select-file-by-whiptail-and-ls"
1317    data-hatena-star-title="whiptailでlsしてファイル選択した結果を取得する"
1318    data-hatena-star-variant="profile-icon"
1319    data-hatena-star-profile-url-template="https://blog.hatena.ne.jp/{username}/"
1320  ></div>
1321
1322
1323    
1324<div class="social-buttons">
1325  
1326  
1327    <div class="social-button-item">
1328      <a href="https://b.hatena.ne.jp/entry/s/www.hacktotech.net/entry/select-file-by-whiptail-and-ls" class="hatena-bookmark-button" data-hatena-bookmark-url="https://www.hacktotech.net/entry/select-file-by-whiptail-and-ls" data-hatena-bookmark-layout="vertical-balloon" data-hatena-bookmark-lang="ja" title="この記事をはてなブックマークに追加"><img src="https://b.st-hatena.com/images/entry-button/button-only.gif" alt="この記事をはてなブックマークに追加" width="20" height="20" style="border: none;" /></a>
1329    </div>
1330  
1331  
1332  
1333    
1334    
1335    <div class="social-button-item">
1336      <a
1337          class="entry-share-button entry-share-button-twitter test-share-button-twitter"
1338          href="https://x.com/intent/tweet?text=whiptail%E3%81%A7ls%E3%81%97%E3%81%A6%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E9%81%B8%E6%8A%9E%E3%81%97%E3%81%9F%E7%B5%90%E6%9E%9C%E3%82%92%E5%8F%96%E5%BE%97%E3%81%99%E3%82%8B+-+HackToTech&amp;url=https%3A%2F%2Fwww.hacktotech.net%2Fentry%2Fselect-file-by-whiptail-and-ls"
1339          title="X(Twitter)で投稿する"
1340        ></a>
1341    </div>
1342  
1343  
1344  
1345  
1346  
1347  
1348</div>
1349
1350    
1351
1352    <div class="customized-footer">
1353      
1354
1355    </div>
1356    
1357
1358  </footer>
1359
1360  </div>
1361</article>
1362
1363      
1364      
1365    
1366  
1367
1368  
1369  <!-- rakuten_ad_target_end -->
1370  <!-- google_ad_section_end -->
1371  
1372
1373  
1374  <div class="pager autopagerize_insert_before">
1375    <span class="pager-next">
1376      <a href="https://www.hacktotech.net/?page=2" rel="next">次のページ</a>
1377    </span>
1378  </div>
1379
1380
1381
1382
1383        </div>
1384      </div>
1385
1386      <aside id="box1">
1387  <div id="box1-inner">
1388  </div>
1389</aside>
1390
1391    </div><!-- #wrapper -->
1392
1393    
1394<aside id="box2">
1395  
1396  <div id="box2-inner">
1397    
1398      
1399
1400<div class="hatena-module hatena-module-profile">
1401  <div class="hatena-module-title">
1402    プロフィール
1403  </div>
1404  <div class="hatena-module-body">
1405    
1406    <a href="https://www.hacktotech.net/about" class="profile-icon-link">
1407      <img src="https://cdn.profile-image.st-hatena.com/users/atr0phy/profile.png?1789619440"
1408      alt="id:atr0phy" class="profile-icon" />
1409    </a>
1410    
1411
1412    
1413
1414    
1415
1416    
1417    <div class="profile-description">
1418      <p>試したことや学んだこと書いてます</p>
1419
1420    </div>
1421    
1422
1423    
1424
1425    
1426
1427    <div class="profile-about">
1428      <a href="https://www.hacktotech.net/about">このブログについて</a>
1429    </div>
1430
1431  </div>
1432</div>
1433
1434    
1435      <div class="hatena-module hatena-module-recent-entries ">
1436  <div class="hatena-module-title">
1437    <a href="https://www.hacktotech.net/archive">
1438      最新記事
1439    </a>
1440  </div>
1441  <div class="hatena-module-body">
1442    <ul class="recent-entries hatena-urllist ">
1443  
1444  
1445    
1446    <li class="urllist-item recent-entries-item">
1447      <div class="urllist-item-inner recent-entries-item-inner">
1448        
1449          
1450          
1451          <a href="https://www.hacktotech.net/entry/mockito-kotlin-value-class" class="urllist-title-link recent-entries-title-link  urllist-title recent-entries-title">mockito-kotlinでvalue classがサポートされたらしいのでメモ</a>
1452
1453
1454
1455
1456          
1457          
1458
1459                </div>
1460    </li>
1461  
1462    
1463    <li class="urllist-item recent-entries-item">
1464      <div class="urllist-item-inner recent-entries-item-inner">
1465        
1466          
1467          
1468          <a href="https://www.hacktotech.net/entry/sbom-memo" class="urllist-title-link recent-entries-title-link  urllist-title recent-entries-title">
1468SBOM周りを見てたのでメモ</a>
1469
1470
1471
1472
1473          
1474          
1475
1476                </div>
1477    </li>
1478  
1479    
1480    <li class="urllist-item recent-entries-item">
1481      <div class="urllist-item-inner recent-entries-item-inner">
1482        
1483          
1484          
1485          <a href="https://www.hacktotech.net/entry/use-spring-milestone-version" class="urllist-title-link recent-entries-title-link  urllist-title recent-entries-title">Springのmilestoneのバージョンを試してたのでメモ</a>
1486
1487
1488
1489
1490          
1491          
1492
1493                </div>
1494    </li>
1495  
1496    
1497    <li class="urllist-item recent-entries-item">
1498      <div class="urllist-item-inner recent-entries-item-inner">
1499        
1500          
1501          
1502          <a href="https://www.hacktotech.net/entry/spring-boot-exception-translator-for-repository-annotation" class="urllist-title-link recent-entries-title-link  urllist-title recent-entries-title">SpringBootで@Repositoryがついたクラスのメソッドから投げられた例外を変換して投げ直す</a>
1503
1504
1505
1506
1507          
1508          
1509
1510                </div>
1511    </li>
1512  
1513    
1514    <li class="urllist-item recent-entries-item">
1515      <div class="urllist-item-inner recent-entries-item-inner">
1516        
1517          
1518          
1519          <a href="https://www.hacktotech.net/entry/select-file-by-whiptail-and-ls" class="urllist-title-link recent-entries-title-link  urllist-title recent-entries-title">whiptailでlsしてファイル選択した結果を取得する</a>
1520
1521
1522
1523
1524          
1525          
1526
1527                </div>
1528    </li>
1529  
1530</ul>
1531
1532      </div>
1533</div>
1534
1535    
1536      
1537
1538<div class="hatena-module hatena-module-category">
1539  <div class="hatena-module-title">
1540    カテゴリー
1541  </div>
1542  <div class="hatena-module-body">
1543    <ul class="hatena-urllist">
1544      
1545        <li>
1546          <a href="https://www.hacktotech.net/archive/category/aws" class="category-aws">
1547            aws (3)
1548          </a>
1549        </li>
1550      
1551        <li>
1552          <a href="https://www.hacktotech.net/archive/category/iam" class="category-iam">
1553            iam (1)
1554          </a>
1555        </li>
1556      
1557        <li>
1558          <a href="https://www.hacktotech.net/archive/category/mockito" class="category-mockito">
1559            mockito (2)
1560          </a>
1561        </li>
1562      
1563        <li>
1564          <a href="https://www.hacktotech.net/archive/category/kotlin" class="category-kotlin">
1565            kotlin (13)
1566          </a>
1567        </li>
1568      
1569        <li>
1570          <a href="https://www.hacktotech.net/archive/category/sbom" class="category-sbom">
1571            sbom (1)
1572          </a>
1573        </li>
1574      
1575        <li>
1576          <a href="https://www.hacktotech.net/archive/category/spring" class="category-spring">
1577            spring (7)
1578          </a>
1579        </li>
1580      
1581        <li>
1582          <a href="https://www.hacktotech.net/archive/category/spring-boot" class="category-spring-boot">
1583            spring-boot (10)
1584          </a>
1585        </li>
1586      
1587        <li>
1588          <a href="https://www.hacktotech.net/archive/category/bash" class="category-bash">
1589            bash (1)
1590          </a>
1591        </li>
1592      
1593        <li>
1594          <a href="https://www.hacktotech.net/archive/category/whiptail" class="category-whiptail">
1595            whiptail (1)
1596          </a>
1597        </li>
1598      
1599        <li>
1600          <a href="https://www.hacktotech.net/archive/category/PGAudit" class="category-PGAudit">
1601            PGAudit (1)
1602          </a>
1603        </li>
1604      
1605        <li>
1606          <a href="https://www.hacktotech.net/archive/category/PostgreSQL" class="category-PostgreSQL">
1607            PostgreSQL (1)
1608          </a>
1609        </li>
1610      
1611        <li>
1612          <a href="https://www.hacktotech.net/archive/category/validation" class="category-validation">
1613            validation (3)
1614          </a>
1615        </li>
1616      
1617        <li>
1618          <a href="https://www.hacktotech.net/archive/category/jvm" class="category-jvm">
1619            jvm (1)
1620          </a>
1621        </li>
1622      
1623        <li>
1624          <a href="https://www.hacktotech.net/archive/category/java" class="category-java">
1625            java (2)
1626          </a>
1627        </li>
1628      
1629        <li>
1630          <a href="https://www.hacktotech.net/archive/category/dependabot" class="category-dependabot">
1631            dependabot (1)
1632          </a>
1633        </li>
1634      
1635        <li>
1636          <a href="https://www.hacktotech.net/archive/category/gradle" class="category-gradle">
1637            gradle (1)
1638          </a>
1639        </li>
1640      
1641        <li>
1642          <a href="https://www.hacktotech.net/archive/category/spring-security" class="category-spring-security">
1643            spring-security (1)
1644          </a>
1645        </li>
1646      
1647        <li>
1648          <a href="https://www.hacktotech.net/archive/category/tomcat" class="category-tomcat">
1649            tomcat (2)
1650          </a>
1651        </li>
1652      
1653        <li>
1654          <a href="https://www.hacktotech.net/archive/category/ubuntu" class="category-ubuntu">
1655            ubuntu (1)
1656          </a>
1657        </li>
1658      
1659        <li>
1660          <a href="https://www.hacktotech.net/archive/category/atlantis" class="category-atlantis">
1661            atlantis (1)
1662          </a>
1663        </li>
1664      
1665        <li>
1666          <a href="https://www.hacktotech.net/archive/category/terraform" class="category-terraform">
1667            terraform (2)
1668          </a>
1669        </li>
1670      
1671        <li>
1672          <a href="https://www.hacktotech.net/archive/category/pgjdbc" class="category-pgjdbc">
1673            pgjdbc (1)
1674          </a>
1675        </li>
1676      
1677        <li>
1678          <a href="https://www.hacktotech.net/archive/category/semver" class="category-semver">
1679            semver (1)
1680          </a>
1681        </li>
1682      
1683        <li>
1684          <a href="https://www.hacktotech.net/archive/category/node.js" class="category-node.js">
1685            node.js (1)
1686          </a>
1687        </li>
1688      
1689        <li>
1690          <a href="https://www.hacktotech.net/archive/category/python" class="category-python">
1691            python (1)
1692          </a>
1693        </li>
1694      
1695        <li>
1696          <a href="https://www.hacktotech.net/archive/category/cdk" class="category-cdk">
1697            cdk (2)
1698          </a>
1699        </li>
1700      
1701        <li>
1702          <a href="https://www.hacktotech.net/archive/category/fargate" class="category-fargate">
1703            fargate (1)
1704          </a>
1705        </li>
1706      
1707        <li>
1708          <a href="https://www.hacktotech.net/archive/category/GC%E6%9C%AC" class="category-GC本">
1709            GC本 (2)
1710          </a>
1711        </li>
1712      
1713        <li>
1714          <a href="https://www.hacktotech.net/archive/category/%E8%AA%AD%E6%9B%B8%E3%83%A1%E3%83%A2" class="category-読書メモ">
1715            読書メモ (2)
1716          </a>
1717        </li>
1718      
1719        <li>
1720          <a href="https://www.hacktotech.net/archive/category/batch" class="category-batch">
1721            batch (1)
1722          </a>
1723        </li>
1724      
1725        <li>
1726          <a href="https://www.hacktotech.net/archive/category/prometheus" class="category-prometheus">
1727            prometheus (1)
1728          </a>
1729        </li>
1730      
1731        <li>
1732          <a href="https://www.hacktotech.net/archive/category/bpf" class="category-bpf">
1733            bpf (10)
1734          </a>
1735        </li>
1736      
1737    </ul>
1738  </div>
1739</div>
1740
1741    
1742      
1743
1744<div class="hatena-module hatena-module-archive" data-archive-type="default" data-archive-url="https://www.hacktotech.net/archive">
1745  <div class="hatena-module-title">
1746    <a href="https://www.hacktotech.net/archive">月別アーカイブ</a>
1747  </div>
1748  <div class="hatena-module-body">
1749    
1750      
1751        <ul class="hatena-urllist">
1752          
1753            <li class="archive-module-year archive-module-year-hidden" data-year="2024">
1754              <div class="archive-module-button">
1755                <span class="archive-module-hide-button">▼</span>
1756                <span class="archive-module-show-button">▶</span>
1757              </div>
1758              <a href="https://www.hacktotech.net/archive/2024" class="archive-module-year-title archive-module-year-2024">
1759                2024
1760              </a>
1761              <ul class="archive-module-months">
1762                
1763                  <li class="archive-module-month">
1764                    <a href="https://www.hacktotech.net/archive/2024/07" class="archive-module-month-title archive-module-month-2024-7">
1765                      2024 / 7
1766                    </a>
1767                  </li>
1768                
1769                  <li class="archive-module-month">
1770                    <a href="https://www.hacktotech.net/archive/2024/05" class="archive-module-month-title archive-module-month-2024-5">
1771                      2024 / 5
1772                    </a>
1773                  </li>
1774                
1775                  <li class="archive-module-month">
1776                    <a href="https://www.hacktotech.net/archive/2024/04" class="archive-module-month-title archive-module-month-2024-4">
1777                      2024 / 4
1778                    </a>
1779                  </li>
1780                
1781                  <li class="archive-module-month">
1782                    <a href="https://www.hacktotech.net/archive/2024/03" class="archive-module-month-title archive-module-month-2024-3">
1783                      2024 / 3
1784                    </a>
1785                  </li>
1786                
1787                  <li class="archive-module-month">
1788                    <a href="https://www.hacktotech.net/archive/2024/01" class="archive-module-month-title archive-module-month-2024-1">
1789                      2024 / 1
1790                    </a>
1791                  </li>
1792                
1793              </ul>
1794            </li>
1795          
1796            <li class="archive-module-year archive-module-year-hidden" data-year="2023">
1797              <div class="archive-module-button">
1798                <span class="archive-module-hide-button">▼</span>
1799                <span class="archive-module-show-button">▶</span>
1800              </div>
1801              <a href="https://www.hacktotech.net/archive/2023" class="archive-module-year-title archive-module-year-2023">
1802                2023
1803              </a>
1804              <ul class="archive-module-months">
1805                
1806                  <li class="archive-module-month">
1807                    <a href="https://www.hacktotech.net/archive/2023/12" class="archive-module-month-title archive-module-month-2023-12">
1808                      2023 / 12
1809                    </a>
1810                  </li>
1811                
1812                  <li class="archive-module-month">
1813                    <a href="https://www.hacktotech.net/archive/2023/11" class="archive-module-month-title archive-module-month-2023-11">
1814                      2023 / 11
1815                    </a>
1816                  </li>
1817                
1818                  <li class="archive-module-month">
1819                    <a href="https://www.hacktotech.net/archive/2023/10" class="archive-module-month-title archive-module-month-2023-10">
1820                      2023 / 10
1821                    </a>
1822                  </li>
1823                
1824                  <li class="archive-module-month">
1825                    <a href="https://www.hacktotech.net/archive/2023/09" class="archive-module-month-title archive-module-month-2023-9">
1826                      2023 / 9
1827                    </a>
1828                  </li>
1829                
1830                  <li class="archive-module-month">
1831                    <a href="https://www.hacktotech.net/archive/2023/08" class="archive-module-month-title archive-module-month-2023-8">
1832                      2023 / 8
1833                    </a>
1834                  </li>
1835                
1836                  <li class="archive-module-month">
1837                    <a href="https://www.hacktotech.net/archive/2023/05" class="archive-module-month-title archive-module-month-2023-5">
1838                      2023 / 5
1839                    </a>
1840                  </li>
1841                
1842                  <li class="archive-module-month">
1843                    <a href="https://www.hacktotech.net/archive/2023/04" class="archive-module-month-title archive-module-month-2023-4">
1844                      2023 / 4
1845                    </a>
1846                  </li>
1847                
1848                  <li class="archive-module-month">
1849                    <a href="https://www.hacktotech.net/archive/2023/03" class="archive-module-month-title archive-module-month-2023-3">
1850                      2023 / 3
1851                    </a>
1852                  </li>
1853                
1854                  <li class="archive-module-month">
1855                    <a href="https://www.hacktotech.net/archive/2023/02" class="archive-module-month-title archive-module-month-2023-2">
1856                      2023 / 2
1857                    </a>
1858                  </li>
1859                
1860                  <li class="archive-module-month">
1861                    <a href="https://www.hacktotech.net/archive/2023/01" class="archive-module-month-title archive-module-month-2023-1">
1862                      2023 / 1
1863                    </a>
1864                  </li>
1865                
1866              </ul>
1867            </li>
1868          
1869            <li class="archive-module-year archive-module-year-hidden" data-year="2022">
1870              <div class="archive-module-button">
1871                <span class="archive-module-hide-button">▼</span>
1872                <span class="archive-module-show-button">▶</span>
1873              </div>
1874              <a href="https://www.hacktotech.net/archive/2022" class="archive-module-year-title archive-module-year-2022">
1875                2022
1876              </a>
1877              <ul class="archive-module-months">
1878                
1879                  <li class="archive-module-month">
1880                    <a href="https://www.hacktotech.net/archive/2022/12" class="archive-module-month-title archive-module-month-2022-12">
1881                      2022 / 12
1882                    </a>
1883                  </li>
1884                
1885                  <li class="archive-module-month">
1886                    <a href="https://www.hacktotech.net/archive/2022/11" class="archive-module-month-title archive-module-month-2022-11">
1887                      2022 / 11
1888                    </a>
1889                  </li>
1890                
1891                  <li class="archive-module-month">
1892                    <a href="https://www.hacktotech.net/archive/2022/07" class="archive-module-month-title archive-module-month-2022-7">
1893                      2022 / 7
1894                    </a>
1895                  </li>
1896                
1897                  <li class="archive-module-month">
1898                    <a href="https://www.hacktotech.net/archive/2022/04" class="archive-module-month-title archive-module-month-2022-4">
1899                      2022 / 4
1900                    </a>
1901                  </li>
1902                
1903                  <li class="archive-module-month">
1904                    <a href="https://www.hacktotech.net/archive/2022/03" class="archive-module-month-title archive-module-month-2022-3">
1905                      2022 / 3
1906                    </a>
1907                  </li>
1908                
1909                  <li class="archive-module-month">
1910                    <a href="https://www.hacktotech.net/archive/2022/02" class="archive-module-month-title archive-module-month-2022-2">
1911                      2022 / 2
1912                    </a>
1913                  </li>
1914                
1915              </ul>
1916            </li>
1917          
1918            <li class="archive-module-year archive-module-year-hidden" data-year="2021">
1919              <div class="archive-module-button">
1920                <span class="archive-module-hide-button">▼</span>
1921                <span class="archive-module-show-button">▶</span>
1922              </div>
1923              <a href="https://www.hacktotech.net/archive/2021" class="archive-module-year-title archive-module-year-2021">
1924                2021
1925              </a>
1926              <ul class="archive-module-months">
1927                
1928                  <li class="archive-module-month">
1929                    <a href="https://www.hacktotech.net/archive/2021/10" class="archive-module-month-title archive-module-month-2021-10">
1930                      2021 / 10
1931                    </a>
1932                  </li>
1933                
1934                  <li class="archive-module-month">
1935                    <a href="https://www.hacktotech.net/archive/2021/07" class="archive-module-month-title archive-module-month-2021-7">
1936                      2021 / 7
1937                    </a>
1938                  </li>
1939                
1940              </ul>
1941            </li>
1942          
1943            <li class="archive-module-year archive-module-year-hidden" data-year="2020">
1944              <div class="archive-module-button">
1945                <span class="archive-module-hide-button">▼</span>
1946                <span class="archive-module-show-button">▶</span>
1947              </div>
1948              <a href="https://www.hacktotech.net/archive/2020" class="archive-module-year-title archive-module-year-2020">
1949                2020
1950              </a>
1951              <ul class="archive-module-months">
1952                
1953                  <li class="archive-module-month">
1954                    <a href="https://www.hacktotech.net/archive/2020/12" class="archive-module-month-title archive-module-month-2020-12">
1955                      2020 / 12
1956                    </a>
1957                  </li>
1958                
1959                  <li class="archive-module-month">
1960                    <a href="https://www.hacktotech.net/archive/2020/11" class="archive-module-month-title archive-module-month-2020-11">
1961                      2020 / 11
1962                    </a>
1963                  </li>
1964                
1965                  <li class="archive-module-month">
1966                    <a href="https://www.hacktotech.net/archive/2020/07" class="archive-module-month-title archive-module-month-2020-7">
1967                      2020 / 7
1968                    </a>
1969                  </li>
1970                
1971                  <li class="archive-module-month">
1972                    <a href="https://www.hacktotech.net/archive/2020/04" class="archive-module-month-title archive-module-month-2020-4">
1973                      2020 / 4
1974                    </a>
1975                  </li>
1976                
1977                  <li class="archive-module-month">
1978                    <a href="https://www.hacktotech.net/archive/2020/01" class="archive-module-month-title archive-module-month-2020-1">
1979                      2020 / 1
1980                    </a>
1981                  </li>
1982                
1983              </ul>
1984            </li>
1985          
1986            <li class="archive-module-year archive-module-year-hidden" data-year="2019">
1987              <div class="archive-module-button">
1988                <span class="archive-module-hide-button">▼</span>
1989                <span class="archive-module-show-button">▶</span>
1990              </div>
1991              <a href="https://www.hacktotech.net/archive/2019" class="archive-module-year-title archive-module-year-2019">
1992                2019
1993              </a>
1994              <ul class="archive-module-months">
1995                
1996                  <li class="archive-module-month">
1997                    <a href="https://www.hacktotech.net/archive/2019/12" class="archive-module-month-title archive-module-month-2019-12">
1998                      2019 / 12
1999                    </a>
2000                  </li>
2001                
2002              </ul>
2003            </li>
2004          
2005        </ul>
2006      
2007    
2008  </div>
2009</div>
2010
2011    
2012  </div>
2013</aside>
2014
2015
2016  </div>
2017</div>
2018
2019
2020
2021
2022      
2023
2024      
2025
2026
2027    </div>
2028  </div>
2029  
2030
2031  
2032  
2032<script async src="https://s.hatena.ne.jp/js/widget/star.js"></script>
2032
2033  
2034  
2035  
2035<script>
2036    if (typeof window.Hatena === 'undefined') {
2037      window.Hatena = {};
2038    }
2039    if (!Hatena.hasOwnProperty('Star')) {
2040      Hatena.Star = {
2041        VERSION: 2,
2042      };
2043    }
2044  </script>
2044
2045
2046
2047  
2048  
2049
2050<div class="quote-box">
2051  <div class="tooltip-quote tooltip-quote-stock">
2052    <i class="blogicon-quote" title="引用をストック"></i>
2053  </div>
2054  <div class="tooltip-quote tooltip-quote-tweet js-tooltip-quote-tweet">
2055    <a class="js-tweet-quote" target="_blank" data-track-name="quote-tweet" data-track-once>
2056      <img src="https://cdn.blog.st-hatena.com/images/admin/quote/quote-x-icon.svg?version=89f69427ebf1344326896140241320" title="引用して投稿する" >
2057    </a>
2058  </div>
2059</div>
2060
2061<div class="quote-stock-panel" id="quote-stock-message-box" style="position: absolute; z-index: 3000">
2062  <div class="message-box" id="quote-stock-succeeded-message" style="display: none">
2063    <p>引用をストックしました</p>
2064    <button class="btn btn-primary" id="quote-stock-show-editor-button" data-track-name="curation-quote-edit-button">ストック一覧を見る</button>
2065    <button class="btn quote-stock-close-message-button">閉じる</button>
2066  </div>
2067
2068  <div class="message-box" id="quote-login-required-message" style="display: none">
2069    <p>引用するにはまずログインしてください</p>
2070    <button class="btn btn-primary" id="quote-login-button">ログイン</button>
2071    <button class="btn quote-stock-close-message-button">閉じる</button>
2072  </div>
2073
2074  <div class="error-box" id="quote-stock-failed-message" style="display: none">
2075    <p>引用をストックできませんでした。再度お試しください</p>
2076    <button class="btn quote-stock-close-message-button">閉じる</button>
2077  </div>
2078
2079  <div class="error-box" id="unstockable-quote-message-box" style="display: none; position: absolute; z-index: 3000;">
2080    <p>限定公開記事のため引用できません。</p>
2081  </div>
2082</div>
2083
2084<script type="x-underscore-template" id="js-requote-button-template">
2085  <div class="requote-button js-requote-button">
2086    <button class="requote-button-btn tipsy-top" title="引用する"><i class="blogicon-quote"></i></button>
2087  </div>
2088</script>
2088
2089
2090
2091
2092  
2093  <div id="hidden-subscribe-button" style="display: none;">
2094    <div class="hatena-follow-button-box btn-subscribe js-hatena-follow-button-box"
2095  
2096  >
2097
2098  <a href="#" class="hatena-follow-button js-hatena-follow-button">
2099    <span class="subscribing">
2100      <span class="foreground">読者です</span>
2101      <span class="background">読者をやめる</span>
2102    </span>
2103    <span class="unsubscribing" data-track-name="profile-widget-subscribe-button" data-track-once>
2104      <span class="foreground">読者になる</span>
2105      <span class="background">読者になる</span>
2106    </span>
2107  </a>
2108  <div class="subscription-count-box js-subscription-count-box">
2109    <i></i>
2110    <u></u>
2111    <span class="subscription-count js-subscription-count">
2112    </span>
2113  </div>
2114</div>
2115
2116  </div>
2117
2118  
2119
2120
2121
2122    
2123
2124
2125  
2125<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
2125
2126
2127<script src="https://b.st-hatena.com/js/bookmark_button.js" charset="utf-8" async="async"></script>
2127
2128
2129
2130<script type="text/javascript" src="https://cdn.blog.st-hatena.com/js/external/jquery.min.js?v=1.12.4&amp;version=89f69427ebf1344326896140241320"></script>
2130
2131
2132
2133
2134
2135
2136
2137
2138<script src="https://cdn.blog.st-hatena.com/js/texts-ja.js?version=89f69427ebf1344326896140241320"></script>
2138
2139
2140
2141
2142  
2142<script id="vendors-js" data-env="production" src="https://cdn.blog.st-hatena.com/js/vendors.js?version=89f69427ebf1344326896140241320" crossorigin="anonymous"></script>
2142
2143
2144<script id="hatenablog-js" data-env="production" src="https://cdn.blog.st-hatena.com/js/hatenablog.js?version=89f69427ebf1344326896140241320" crossorigin="anonymous" data-page-id="index"></script>
2144
2145
2146
2147  
2147<script>Hatena.Diary.GlobalHeader.init()</script>
2147
2148
2149
2150
2151
2152
2153
2154
2155    
2156
2157    
2158
2159
2160
2161
2162
2163  </body>
2164</html>

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.