{"data":{"post":{"fields":{"slug":"/jpa-and-uuid/","date":"2018-10-24"},"html":"<h2>Long story short</h2>\n<p>Using a manually generated id in your entities, you should initialize it no later than when\ninstantiating the the object to avoid null value comparison in <code class=\"language-text\">equals()</code> if storing instances\nin a <code class=\"language-text\">Set</code>. <code class=\"language-text\">@PrePersist</code> is too late or you’ll end up with only one persisted object out of the\nwhole collection.</p>\n<p>You can still achieve this if using <code class=\"language-text\">Lombok</code>’s <code class=\"language-text\">Builder</code> and the <code class=\"language-text\">@Builder.Default</code> feature.</p>\n<h2>Best practices in place - what can possibly go wrong?</h2>\n<h3>Manually generated UUID</h3>\n<p>In our JPA-mapped project, we had <code class=\"language-text\">Venue</code>s and <code class=\"language-text\">Price</code>s in a <code class=\"language-text\">One-to-many</code> relationship -\neach venue can have several prices, keeping them in a <code class=\"language-text\">Set</code>. Being all good boys and girls here,\nwe had them identified by UUIDs. We generated the UUIDs using the <code class=\"language-text\">javax.persistence.PrePersist</code>\nevent listener:   </p>\n<div class=\"gatsby-highlight\" data-language=\"java\"><pre class=\"language-java\"><code class=\"language-java\"><span class=\"token keyword\">public</span> <span class=\"token keyword\">class</span> <span class=\"token class-name\">Price</span> <span class=\"token punctuation\">{</span>\n  <span class=\"token annotation punctuation\">@Id</span>\n  <span class=\"token annotation punctuation\">@Type</span><span class=\"token punctuation\">(</span>type <span class=\"token operator\">=</span> <span class=\"token string\">\"pg-uuid\"</span><span class=\"token punctuation\">)</span>\n  <span class=\"token annotation punctuation\">@Column</span><span class=\"token punctuation\">(</span>unique <span class=\"token operator\">=</span> <span class=\"token boolean\">true</span><span class=\"token punctuation\">,</span> nullable <span class=\"token operator\">=</span> <span class=\"token boolean\">false</span><span class=\"token punctuation\">,</span> columnDefinition <span class=\"token operator\">=</span> <span class=\"token string\">\"uuid\"</span><span class=\"token punctuation\">)</span>\n  <span class=\"token keyword\">private</span> UUID id<span class=\"token punctuation\">;</span>\n\n  <span class=\"token comment\">// other fields...</span>\n  \n  <span class=\"token annotation punctuation\">@PrePersist</span>\n  <span class=\"token keyword\">public</span> <span class=\"token keyword\">void</span> <span class=\"token function\">prePersist</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n    id <span class=\"token operator\">=</span> UUID<span class=\"token punctuation\">.</span><span class=\"token function\">randomUUID</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n  <span class=\"token punctuation\">}</span>\n  \n<span class=\"token punctuation\">}</span></code></pre></div>\n<h3>Implemented <code class=\"language-text\">equals()</code> and <code class=\"language-text\">hashCode()</code></h3>\n<p>As good girls and boys, we also know we should take care of a proper <code class=\"language-text\">equals()</code> and <code class=\"language-text\">hashCode</code>\nimplementation, which in case of JPA entities comes down to comparing the unique id:</p>\n<div class=\"gatsby-highlight\" data-language=\"java\"><pre class=\"language-java\"><code class=\"language-java\"><span class=\"token annotation punctuation\">@Builder</span>\n<span class=\"token annotation punctuation\">@Entity</span>\n<span class=\"token keyword\">public</span> <span class=\"token keyword\">class</span> <span class=\"token class-name\">Price</span> <span class=\"token punctuation\">{</span>\n<span class=\"token comment\">// ...</span>\n  <span class=\"token annotation punctuation\">@Override</span>\n  <span class=\"token keyword\">public</span> <span class=\"token keyword\">boolean</span> <span class=\"token function\">equals</span><span class=\"token punctuation\">(</span>Object o<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span><span class=\"token keyword\">this</span> <span class=\"token operator\">==</span> o<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n      <span class=\"token keyword\">return</span> <span class=\"token boolean\">true</span><span class=\"token punctuation\">;</span>\n    <span class=\"token punctuation\">}</span>\n    <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span>o <span class=\"token operator\">==</span> null <span class=\"token operator\">||</span> <span class=\"token function\">getClass</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">!=</span> o<span class=\"token punctuation\">.</span><span class=\"token function\">getClass</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n      <span class=\"token keyword\">return</span> <span class=\"token boolean\">false</span><span class=\"token punctuation\">;</span>\n    <span class=\"token punctuation\">}</span>\n    Price price <span class=\"token operator\">=</span> <span class=\"token punctuation\">(</span>Price<span class=\"token punctuation\">)</span> o<span class=\"token punctuation\">;</span>\n    <span class=\"token keyword\">return</span> Objects<span class=\"token punctuation\">.</span><span class=\"token function\">equals</span><span class=\"token punctuation\">(</span>id<span class=\"token punctuation\">,</span> price<span class=\"token punctuation\">.</span>id<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n  <span class=\"token punctuation\">}</span>\n\n  <span class=\"token annotation punctuation\">@Override</span>\n  <span class=\"token keyword\">public</span> <span class=\"token keyword\">int</span> <span class=\"token function\">hashCode</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token keyword\">return</span> Objects<span class=\"token punctuation\">.</span><span class=\"token function\">hash</span><span class=\"token punctuation\">(</span>id<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n  <span class=\"token punctuation\">}</span>\n <span class=\"token comment\">// ...</span></code></pre></div>\n<p>(Here we’d like to say “hi” to one of our favorite writers\n<a href=\"https://dzone.com/articles/why-should-you-care-about-equals-and-hashcode\">Jakub Kubryński</a> )</p>\n<h3>Let’s get all the credit</h3>\n<p>So far so good. In the above setting, <code class=\"language-text\">Venue</code> is the managing entity, and <code class=\"language-text\">PERSIST</code> is one of\nthe cascaded operations, so adding a few prices to a venue is as simple as:</p>\n<div class=\"gatsby-highlight\" data-language=\"java\"><pre class=\"language-java\"><code class=\"language-java\">  gasStation<span class=\"token punctuation\">.</span><span class=\"token function\">getPrices</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span><span class=\"token function\">addAll</span><span class=\"token punctuation\">(</span>Set<span class=\"token punctuation\">.</span><span class=\"token function\">of</span><span class=\"token punctuation\">(</span>\n          Price<span class=\"token punctuation\">.</span><span class=\"token function\">builder</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span>\n              <span class=\"token punctuation\">.</span><span class=\"token function\">priceType</span><span class=\"token punctuation\">(</span>PriceType<span class=\"token punctuation\">.</span>REGULAR<span class=\"token punctuation\">)</span>\n              <span class=\"token punctuation\">.</span><span class=\"token function\">price</span><span class=\"token punctuation\">(</span><span class=\"token keyword\">new</span> <span class=\"token class-name\">BigDecimal</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"12.345\"</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span>\n              <span class=\"token punctuation\">.</span><span class=\"token function\">venue</span><span class=\"token punctuation\">(</span>gasStation<span class=\"token punctuation\">)</span>\n              <span class=\"token punctuation\">.</span><span class=\"token function\">build</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span>\n          Price<span class=\"token punctuation\">.</span><span class=\"token function\">builder</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span>\n              <span class=\"token punctuation\">.</span><span class=\"token function\">priceType</span><span class=\"token punctuation\">(</span>PriceType<span class=\"token punctuation\">.</span>DIESEL<span class=\"token punctuation\">)</span>\n              <span class=\"token punctuation\">.</span><span class=\"token function\">price</span><span class=\"token punctuation\">(</span><span class=\"token keyword\">new</span> <span class=\"token class-name\">BigDecimal</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"34.345\"</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span>\n              <span class=\"token punctuation\">.</span><span class=\"token function\">venue</span><span class=\"token punctuation\">(</span>gasStation<span class=\"token punctuation\">)</span>\n              <span class=\"token punctuation\">.</span><span class=\"token function\">build</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span>\n      <span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></code></pre></div>\n<p>(since we also use the pretty <code class=\"language-text\">@Builder</code> syntax, generated for us by Lombok).</p>\n<p>…but no. A single price will be created correctly, but since <code class=\"language-text\">Objects.equals()</code> implementation\nis such that a <code class=\"language-text\">null</code> equals a <code class=\"language-text\">null</code>, two freshly created prices with a <code class=\"language-text\">uuid = null</code> will be\ntreated as equal by the <code class=\"language-text\">Set</code> implementation and in result… only the one added last will be\nstored in the database! </p>\n<p>This is definitely not what we had in mind.</p>\n<p>Side note: We were lucky enough to have discovered this thanks to having some test coverage\nas well as using Java9’s <code class=\"language-text\">java.util.ImmutableCollections</code> which gave us the following error,\nclearly indicating our problem:</p>\n<div class=\"gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">java.lang.IllegalArgumentException: duplicate element: Price(id=null, price=12.345, priceType=REGULAR, createdAt=null)\n\n\tat java.base/java.util.ImmutableCollections$Set2.&lt;init&gt;(ImmutableCollections.java:380)\n\tat java.base/java.util.Set.of(Set.java:484) </code></pre></div>\n<h2>Solving the problem</h2>\n<p>If the <code class=\"language-text\">@PrePersist</code> phase is too late for generating the UUID for our needs, why not use\nfield initialization, like that?</p>\n<div class=\"gatsby-highlight\" data-language=\"java\"><pre class=\"language-java\"><code class=\"language-java\"><span class=\"token annotation punctuation\">@Builder</span>\n<span class=\"token annotation punctuation\">@Entity</span>\n<span class=\"token keyword\">public</span> <span class=\"token keyword\">class</span> <span class=\"token class-name\">Price</span> <span class=\"token punctuation\">{</span>\n  <span class=\"token annotation punctuation\">@Id</span>\n  <span class=\"token annotation punctuation\">@Type</span><span class=\"token punctuation\">(</span>type <span class=\"token operator\">=</span> <span class=\"token string\">\"pg-uuid\"</span><span class=\"token punctuation\">)</span>\n  <span class=\"token annotation punctuation\">@Column</span><span class=\"token punctuation\">(</span>unique <span class=\"token operator\">=</span> <span class=\"token boolean\">true</span><span class=\"token punctuation\">,</span> nullable <span class=\"token operator\">=</span> <span class=\"token boolean\">false</span><span class=\"token punctuation\">,</span> columnDefinition <span class=\"token operator\">=</span> <span class=\"token string\">\"uuid\"</span><span class=\"token punctuation\">)</span>\n  <span class=\"token keyword\">private</span> UUID id <span class=\"token operator\">=</span> UUID<span class=\"token punctuation\">.</span><span class=\"token function\">randomUUID</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n  <span class=\"token punctuation\">}</span></code></pre></div>\n<p>Well, almost. This would have worked if we hadn’t used the goodness of <code class=\"language-text\">Lombok&#39;s</code> <code class=\"language-text\">@Builder</code>\nwhose own fields override the <code class=\"language-text\">Price</code> object’s fields the moment we call <code class=\"language-text\">build()</code>.</p>\n<h3>The new hope</h3>\n<p>Fortunately, <code class=\"language-text\">Lombok</code> didn’t leave us alone in our misery and provided a tool to preserve\nthe initial value of a <code class=\"language-text\">@Builder</code> - decorated class. It’s the <code class=\"language-text\">@Builder.Default</code> annotation\nand we use it like this:</p>\n<div class=\"gatsby-highlight\" data-language=\"java\"><pre class=\"language-java\"><code class=\"language-java\"><span class=\"token annotation punctuation\">@Builder</span>\n<span class=\"token annotation punctuation\">@Entity</span>\n<span class=\"token keyword\">public</span> <span class=\"token keyword\">class</span> <span class=\"token class-name\">Price</span> <span class=\"token punctuation\">{</span>\n\n  <span class=\"token annotation punctuation\">@Id</span>\n  <span class=\"token annotation punctuation\">@Type</span><span class=\"token punctuation\">(</span>type <span class=\"token operator\">=</span> <span class=\"token string\">\"pg-uuid\"</span><span class=\"token punctuation\">)</span>\n  <span class=\"token annotation punctuation\">@Column</span><span class=\"token punctuation\">(</span>unique <span class=\"token operator\">=</span> <span class=\"token boolean\">true</span><span class=\"token punctuation\">,</span> nullable <span class=\"token operator\">=</span> <span class=\"token boolean\">false</span><span class=\"token punctuation\">,</span> columnDefinition <span class=\"token operator\">=</span> <span class=\"token string\">\"uuid\"</span><span class=\"token punctuation\">)</span>\n  <span class=\"token annotation punctuation\">@Builder</span><span class=\"token punctuation\">.</span>Default\n  <span class=\"token keyword\">private</span> UUID id <span class=\"token operator\">=</span> UUID<span class=\"token punctuation\">.</span><span class=\"token function\">randomUUID</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<p>Ta-da, persistence functionality is saved, all <code class=\"language-text\">Price</code> instances get stored, and we can still use\nthe pretty <code class=\"language-text\">@Builder</code> generated by Lombok.</p>\n<h2>Conclusions</h2>\n<ol>\n<li><code class=\"language-text\">@PrePersist</code> is too late for programmatically generating an id,</li>\n<li>Many thanks to the <code class=\"language-text\">Lombok</code> team for including the <code class=\"language-text\">Builder.Default</code> annotation, otherwise\nwe’d have to give up using <code class=\"language-text\">Builder</code> on this class,</li>\n<li>All hail to <code class=\"language-text\">Java9</code> and its <code class=\"language-text\">ImmutableCollections</code> for their validation and nice error messages.</li>\n</ol>\n<p>Hope you save some time and trouble with this couple of tips!</p>\n<p>Don’t hesitate to <a href=\"https://twitter.com/AnnaSkawinska\">reach out</a>.</p>","frontmatter":{"title":"JPA and UUID","subTitle":"And why @PrePersist is bad for your entity","postAuthor":"Anna Skawińska","cover":"/img/java.png"}},"tags":{"group":[{"name":"$OSTYPE","totalCount":1,"edges":[{"node":{"fields":{"slug":"/cross-system-xdebug-docker-compose-setup/"}}}]},{"name":".env","totalCount":1,"edges":[{"node":{"fields":{"slug":"/cross-system-xdebug-docker-compose-setup/"}}}]},{"name":".nvrmc","totalCount":1,"edges":[{"node":{"fields":{"slug":"/travis-problematic-python-and-node/"}}}]},{"name":"AUTO_INCREMENT","totalCount":1,"edges":[{"node":{"fields":{"slug":"/is-mysql-autoincrement-really-monotonic/"}}}]},{"name":"Angular","totalCount":1,"edges":[{"node":{"fields":{"slug":"/Dev-and-prod-ready-Docker-setup-for-SPA-app/"}}}]},{"name":"Command","totalCount":1,"edges":[{"node":{"fields":{"slug":"/complex-command-handler-in-javascript/"}}}]},{"name":"DQL","totalCount":2,"edges":[{"node":{"fields":{"slug":"/doctrine-new-dql-operator-and-objects/"}}},{"node":{"fields":{"slug":"/mysql-decimal-format/"}}}]},{"name":"Data Transfer Object","totalCount":1,"edges":[{"node":{"fields":{"slug":"/doctrine-new-dql-operator-and-objects/"}}}]},{"name":"Docker","totalCount":3,"edges":[{"node":{"fields":{"slug":"/cross-system-xdebug-docker-compose-setup/"}}},{"node":{"fields":{"slug":"/quick-import-of-mysql-database-dump/"}}},{"node":{"fields":{"slug":"/Dev-and-prod-ready-Docker-setup-for-SPA-app/"}}}]},{"name":"Docker Compose","totalCount":3,"edges":[{"node":{"fields":{"slug":"/cross-system-xdebug-docker-compose-setup/"}}},{"node":{"fields":{"slug":"/quick-import-of-mysql-database-dump/"}}},{"node":{"fields":{"slug":"/Dev-and-prod-ready-Docker-setup-for-SPA-app/"}}}]},{"name":"Doctrine","totalCount":2,"edges":[{"node":{"fields":{"slug":"/doctrine-new-dql-operator-and-objects/"}}},{"node":{"fields":{"slug":"/mysql-decimal-format/"}}}]},{"name":"Doctrine NEW","totalCount":1,"edges":[{"node":{"fields":{"slug":"/doctrine-new-dql-operator-and-objects/"}}}]},{"name":"ES7","totalCount":1,"edges":[{"node":{"fields":{"slug":"/async-await-with-express/"}}}]},{"name":"Elastica","totalCount":1,"edges":[{"node":{"fields":{"slug":"/elasticsearch-script-unknown-field-source-parser-not-found/"}}}]},{"name":"Elasticsearch","totalCount":1,"edges":[{"node":{"fields":{"slug":"/elasticsearch-script-unknown-field-source-parser-not-found/"}}}]},{"name":"Elasticsearch script","totalCount":1,"edges":[{"node":{"fields":{"slug":"/elasticsearch-script-unknown-field-source-parser-not-found/"}}}]},{"name":"Express","totalCount":1,"edges":[{"node":{"fields":{"slug":"/async-await-with-express/"}}}]},{"name":"Git","totalCount":2,"edges":[{"node":{"fields":{"slug":"/git-not-detecting-renames-quick-workarounds/"}}},{"node":{"fields":{"slug":"/git-reverting-branch-removal/"}}}]},{"name":"Git renamed","totalCount":1,"edges":[{"node":{"fields":{"slug":"/git-not-detecting-renames-quick-workarounds/"}}}]},{"name":"HTTP","totalCount":1,"edges":[{"node":{"fields":{"slug":"/how-does-slack-communicate-with-spotify/"}}}]},{"name":"JavaScript","totalCount":3,"edges":[{"node":{"fields":{"slug":"/async-await-with-express/"}}},{"node":{"fields":{"slug":"/complex-command-handler-in-javascript/"}}},{"node":{"fields":{"slug":"/how-to-implement-redux-in-react/"}}}]},{"name":"Kafka","totalCount":1,"edges":[{"node":{"fields":{"slug":"/is-mysql-autoincrement-really-monotonic/"}}}]},{"name":"MySQL","totalCount":4,"edges":[{"node":{"fields":{"slug":"/mysql-decimal-format/"}}},{"node":{"fields":{"slug":"/is-mysql-autoincrement-really-monotonic/"}}},{"node":{"fields":{"slug":"/php-with-mysql-8/"}}},{"node":{"fields":{"slug":"/quick-import-of-mysql-database-dump/"}}}]},{"name":"MySQL 8","totalCount":1,"edges":[{"node":{"fields":{"slug":"/php-with-mysql-8/"}}}]},{"name":"Node.js","totalCount":1,"edges":[{"node":{"fields":{"slug":"/travis-problematic-python-and-node/"}}}]},{"name":"ORM","totalCount":1,"edges":[{"node":{"fields":{"slug":"/doctrine-new-dql-operator-and-objects/"}}}]},{"name":"PDO","totalCount":1,"edges":[{"node":{"fields":{"slug":"/php-with-mysql-8/"}}}]},{"name":"PDO_MYSQL","totalCount":1,"edges":[{"node":{"fields":{"slug":"/php-with-mysql-8/"}}}]},{"name":"PHP","totalCount":6,"edges":[{"node":{"fields":{"slug":"/doctrine-new-dql-operator-and-objects/"}}},{"node":{"fields":{"slug":"/mysql-decimal-format/"}}},{"node":{"fields":{"slug":"/cross-system-xdebug-docker-compose-setup/"}}},{"node":{"fields":{"slug":"/php-with-mysql-8/"}}},{"node":{"fields":{"slug":"/elasticsearch-script-unknown-field-source-parser-not-found/"}}},{"node":{"fields":{"slug":"/how-to-write-a-phing-target-autocomplete-bash-script/"}}}]},{"name":"Phing","totalCount":1,"edges":[{"node":{"fields":{"slug":"/how-to-write-a-phing-target-autocomplete-bash-script/"}}}]},{"name":"Promise","totalCount":1,"edges":[{"node":{"fields":{"slug":"/complex-command-handler-in-javascript/"}}}]},{"name":"Python","totalCount":1,"edges":[{"node":{"fields":{"slug":"/travis-problematic-python-and-node/"}}}]},{"name":"React","totalCount":2,"edges":[{"node":{"fields":{"slug":"/how-to-implement-redux-in-react/"}}},{"node":{"fields":{"slug":"/Dev-and-prod-ready-Docker-setup-for-SPA-app/"}}}]},{"name":"Redux","totalCount":1,"edges":[{"node":{"fields":{"slug":"/how-to-implement-redux-in-react/"}}}]},{"name":"Redux store","totalCount":1,"edges":[{"node":{"fields":{"slug":"/how-to-implement-redux-in-react/"}}}]},{"name":"SPA","totalCount":1,"edges":[{"node":{"fields":{"slug":"/Dev-and-prod-ready-Docker-setup-for-SPA-app/"}}}]},{"name":"Slack","totalCount":1,"edges":[{"node":{"fields":{"slug":"/how-does-slack-communicate-with-spotify/"}}}]},{"name":"Spotify","totalCount":1,"edges":[{"node":{"fields":{"slug":"/how-does-slack-communicate-with-spotify/"}}}]},{"name":"Travis","totalCount":2,"edges":[{"node":{"fields":{"slug":"/travis-problematic-python-and-node/"}}},{"node":{"fields":{"slug":"/elasticsearch-script-unknown-field-source-parser-not-found/"}}}]},{"name":"Vue","totalCount":1,"edges":[{"node":{"fields":{"slug":"/Dev-and-prod-ready-Docker-setup-for-SPA-app/"}}}]},{"name":"XDEBUG_CONFIG","totalCount":1,"edges":[{"node":{"fields":{"slug":"/cross-system-xdebug-docker-compose-setup/"}}}]},{"name":"XDebug","totalCount":1,"edges":[{"node":{"fields":{"slug":"/cross-system-xdebug-docker-compose-setup/"}}}]},{"name":"ai","totalCount":1,"edges":[{"node":{"fields":{"slug":"/weekly-ai-bites-last-manual-gap-qa-testing/"}}}]},{"name":"amazon","totalCount":1,"edges":[{"node":{"fields":{"slug":"/minio-as-s3-replacement-in-development-and-beyond/"}}}]},{"name":"apple-watch","totalCount":1,"edges":[{"node":{"fields":{"slug":"/aws-cognito-without-library/"}}}]},{"name":"asp.net core","totalCount":1,"edges":[{"node":{"fields":{"slug":"/net-in-my-browser/"}}}]},{"name":"async","totalCount":2,"edges":[{"node":{"fields":{"slug":"/async-await-with-express/"}}},{"node":{"fields":{"slug":"/complex-command-handler-in-javascript/"}}}]},{"name":"autocomplete","totalCount":1,"edges":[{"node":{"fields":{"slug":"/how-to-write-a-phing-target-autocomplete-bash-script/"}}}]},{"name":"await","totalCount":2,"edges":[{"node":{"fields":{"slug":"/async-await-with-express/"}}},{"node":{"fields":{"slug":"/complex-command-handler-in-javascript/"}}}]},{"name":"aws","totalCount":3,"edges":[{"node":{"fields":{"slug":"/minio-as-s3-replacement-in-development-and-beyond/"}}},{"node":{"fields":{"slug":"/time-out-of-sync-in-aws-ec2/"}}},{"node":{"fields":{"slug":"/aws-cognito-without-library/"}}}]},{"name":"aws.cli","totalCount":1,"edges":[{"node":{"fields":{"slug":"/travis-problematic-python-and-node/"}}}]},{"name":"bash","totalCount":2,"edges":[{"node":{"fields":{"slug":"/cross-system-xdebug-docker-compose-setup/"}}},{"node":{"fields":{"slug":"/how-to-write-a-phing-target-autocomplete-bash-script/"}}}]},{"name":"bitbucket","totalCount":1,"edges":[{"node":{"fields":{"slug":"/how-to-quickly-remove-merged-remote-branches/"}}}]},{"name":"blazor","totalCount":1,"edges":[{"node":{"fields":{"slug":"/net-in-my-browser/"}}}]},{"name":"build","totalCount":1,"edges":[{"node":{"fields":{"slug":"/Dev-and-prod-ready-Docker-setup-for-SPA-app/"}}}]},{"name":"builder pattern","totalCount":1,"edges":[{"node":{"fields":{"slug":"/make-jaxb-great-again/"}}}]},{"name":"c#","totalCount":1,"edges":[{"node":{"fields":{"slug":"/net-in-my-browser/"}}}]},{"name":"ci","totalCount":1,"edges":[{"node":{"fields":{"slug":"/unresolved-check-from-travis-on-github-pull-request/"}}}]},{"name":"claude-code","totalCount":1,"edges":[{"node":{"fields":{"slug":"/weekly-ai-bites-last-manual-gap-qa-testing/"}}}]},{"name":"cognito","totalCount":1,"edges":[{"node":{"fields":{"slug":"/aws-cognito-without-library/"}}}]},{"name":"colors","totalCount":1,"edges":[{"node":{"fields":{"slug":"/naming-sass-color-variables/"}}}]},{"name":"continuous integration","totalCount":1,"edges":[{"node":{"fields":{"slug":"/unresolved-check-from-travis-on-github-pull-request/"}}}]},{"name":"decimal","totalCount":1,"edges":[{"node":{"fields":{"slug":"/mysql-decimal-format/"}}}]},{"name":"docker","totalCount":1,"edges":[{"node":{"fields":{"slug":"/minio-as-s3-replacement-in-development-and-beyond/"}}}]},{"name":"ec2","totalCount":1,"edges":[{"node":{"fields":{"slug":"/time-out-of-sync-in-aws-ec2/"}}}]},{"name":"environment","totalCount":1,"edges":[{"node":{"fields":{"slug":"/Dev-and-prod-ready-Docker-setup-for-SPA-app/"}}}]},{"name":"equals","totalCount":1,"edges":[{"node":{"fields":{"slug":"/jpa-and-uuid/"}}}]},{"name":"flysystem","totalCount":1,"edges":[{"node":{"fields":{"slug":"/minio-as-s3-replacement-in-development-and-beyond/"}}}]},{"name":"front-end","totalCount":1,"edges":[{"node":{"fields":{"slug":"/net-in-my-browser/"}}}]},{"name":"git","totalCount":1,"edges":[{"node":{"fields":{"slug":"/how-to-quickly-remove-merged-remote-branches/"}}}]},{"name":"git commit","totalCount":1,"edges":[{"node":{"fields":{"slug":"/git-not-detecting-renames-quick-workarounds/"}}}]},{"name":"git reflog","totalCount":1,"edges":[{"node":{"fields":{"slug":"/git-reverting-branch-removal/"}}}]},{"name":"git status","totalCount":1,"edges":[{"node":{"fields":{"slug":"/git-not-detecting-renames-quick-workarounds/"}}}]},{"name":"github","totalCount":3,"edges":[{"node":{"fields":{"slug":"/pull-request-templates-on-github/"}}},{"node":{"fields":{"slug":"/unresolved-check-from-travis-on-github-pull-request/"}}},{"node":{"fields":{"slug":"/how-to-quickly-remove-merged-remote-branches/"}}}]},{"name":"guide","totalCount":1,"edges":[{"node":{"fields":{"slug":"/Dev-and-prod-ready-Docker-setup-for-SPA-app/"}}}]},{"name":"hashcode","totalCount":1,"edges":[{"node":{"fields":{"slug":"/jpa-and-uuid/"}}}]},{"name":"hibernate","totalCount":1,"edges":[{"node":{"fields":{"slug":"/jpa-and-uuid/"}}}]},{"name":"java","totalCount":2,"edges":[{"node":{"fields":{"slug":"/make-jaxb-great-again/"}}},{"node":{"fields":{"slug":"/jpa-and-uuid/"}}}]},{"name":"java.time","totalCount":1,"edges":[{"node":{"fields":{"slug":"/make-jaxb-great-again/"}}}]},{"name":"jaxb","totalCount":1,"edges":[{"node":{"fields":{"slug":"/make-jaxb-great-again/"}}}]},{"name":"jdk8","totalCount":1,"edges":[{"node":{"fields":{"slug":"/make-jaxb-great-again/"}}}]},{"name":"jpa","totalCount":1,"edges":[{"node":{"fields":{"slug":"/jpa-and-uuid/"}}}]},{"name":"maven","totalCount":1,"edges":[{"node":{"fields":{"slug":"/make-jaxb-great-again/"}}}]},{"name":"middleware","totalCount":1,"edges":[{"node":{"fields":{"slug":"/how-to-implement-redux-in-react/"}}}]},{"name":"mono","totalCount":1,"edges":[{"node":{"fields":{"slug":"/net-in-my-browser/"}}}]},{"name":"multi-stage","totalCount":1,"edges":[{"node":{"fields":{"slug":"/Dev-and-prod-ready-Docker-setup-for-SPA-app/"}}}]},{"name":"naming","totalCount":1,"edges":[{"node":{"fields":{"slug":"/naming-sass-color-variables/"}}}]},{"name":"networking","totalCount":1,"edges":[{"node":{"fields":{"slug":"/time-out-of-sync-in-aws-ec2/"}}}]},{"name":"ntp","totalCount":1,"edges":[{"node":{"fields":{"slug":"/time-out-of-sync-in-aws-ec2/"}}}]},{"name":"nvm","totalCount":1,"edges":[{"node":{"fields":{"slug":"/travis-problematic-python-and-node/"}}}]},{"name":"persistence","totalCount":1,"edges":[{"node":{"fields":{"slug":"/jpa-and-uuid/"}}}]},{"name":"port 4381","totalCount":1,"edges":[{"node":{"fields":{"slug":"/how-does-slack-communicate-with-spotify/"}}}]},{"name":"pr","totalCount":1,"edges":[{"node":{"fields":{"slug":"/pull-request-templates-on-github/"}}}]},{"name":"production","totalCount":1,"edges":[{"node":{"fields":{"slug":"/Dev-and-prod-ready-Docker-setup-for-SPA-app/"}}}]},{"name":"project","totalCount":1,"edges":[{"node":{"fields":{"slug":"/pull-request-templates-on-github/"}}}]},{"name":"pull","totalCount":1,"edges":[{"node":{"fields":{"slug":"/pull-request-templates-on-github/"}}}]},{"name":"qa","totalCount":1,"edges":[{"node":{"fields":{"slug":"/weekly-ai-bites-last-manual-gap-qa-testing/"}}}]},{"name":"razor","totalCount":1,"edges":[{"node":{"fields":{"slug":"/net-in-my-browser/"}}}]},{"name":"reducer","totalCount":1,"edges":[{"node":{"fields":{"slug":"/how-to-implement-redux-in-react/"}}}]},{"name":"regex","totalCount":1,"edges":[{"node":{"fields":{"slug":"/how-to-write-a-phing-target-autocomplete-bash-script/"}}}]},{"name":"repo","totalCount":1,"edges":[{"node":{"fields":{"slug":"/how-to-quickly-remove-merged-remote-branches/"}}}]},{"name":"repository","totalCount":1,"edges":[{"node":{"fields":{"slug":"/how-to-quickly-remove-merged-remote-branches/"}}}]},{"name":"s3","totalCount":1,"edges":[{"node":{"fields":{"slug":"/minio-as-s3-replacement-in-development-and-beyond/"}}}]},{"name":"sass","totalCount":1,"edges":[{"node":{"fields":{"slug":"/naming-sass-color-variables/"}}}]},{"name":"setup","totalCount":1,"edges":[{"node":{"fields":{"slug":"/Dev-and-prod-ready-Docker-setup-for-SPA-app/"}}}]},{"name":"skills","totalCount":1,"edges":[{"node":{"fields":{"slug":"/weekly-ai-bites-last-manual-gap-qa-testing/"}}}]},{"name":"styles","totalCount":1,"edges":[{"node":{"fields":{"slug":"/naming-sass-color-variables/"}}}]},{"name":"symfony","totalCount":1,"edges":[{"node":{"fields":{"slug":"/minio-as-s3-replacement-in-development-and-beyond/"}}}]},{"name":"templates","totalCount":1,"edges":[{"node":{"fields":{"slug":"/pull-request-templates-on-github/"}}}]},{"name":"test-automation","totalCount":1,"edges":[{"node":{"fields":{"slug":"/weekly-ai-bites-last-manual-gap-qa-testing/"}}}]},{"name":"transaction","totalCount":1,"edges":[{"node":{"fields":{"slug":"/is-mysql-autoincrement-really-monotonic/"}}}]},{"name":"travis","totalCount":1,"edges":[{"node":{"fields":{"slug":"/unresolved-check-from-travis-on-github-pull-request/"}}}]},{"name":"tutorial","totalCount":2,"edges":[{"node":{"fields":{"slug":"/how-to-implement-redux-in-react/"}}},{"node":{"fields":{"slug":"/Dev-and-prod-ready-Docker-setup-for-SPA-app/"}}}]},{"name":"ubuntu","totalCount":1,"edges":[{"node":{"fields":{"slug":"/time-out-of-sync-in-aws-ec2/"}}}]},{"name":"unsupported","totalCount":1,"edges":[{"node":{"fields":{"slug":"/aws-cognito-without-library/"}}}]},{"name":"uuid","totalCount":1,"edges":[{"node":{"fields":{"slug":"/jpa-and-uuid/"}}}]},{"name":"variables","totalCount":1,"edges":[{"node":{"fields":{"slug":"/naming-sass-color-variables/"}}}]},{"name":"wasm","totalCount":1,"edges":[{"node":{"fields":{"slug":"/net-in-my-browser/"}}}]},{"name":"watchos","totalCount":1,"edges":[{"node":{"fields":{"slug":"/aws-cognito-without-library/"}}}]},{"name":"web","totalCount":1,"edges":[{"node":{"fields":{"slug":"/net-in-my-browser/"}}}]}]},"author":{"id":"37bda159-ff45-50c9-aeba-18326b7ca66b","childMarkdownRemark":{"html":"<p><strong>XSolve</strong> We are Agile Software House focused on PHP/Symfony, #JavaScript, #Java and #Mobile (iOS, Android, Windows Phone) #Inc5000 European company in 2018.\n<br>\n<a href=\"https://xsolve.software\">xsolve.software</a></p>"}},"footnote":{"id":"b4474c9b-7be6-5f34-866a-cdfffa885bce","childMarkdownRemark":{"html":"<ul>\n<li>From <a href=\"https://www.boldare.com/\">Boldare</a></li>\n<li>with <a href=\"https://github.com/greglobinski/gatsby-starter-personal-blog/\">Gatsby starter</a></li>\n<li>delivered by <a href=\"https://www.netlify.com/\">Netlify</a></li>\n</ul>"}},"site":{"siteMetadata":{"facebook":{"appId":""}}}},"pageContext":{"slug":"/jpa-and-uuid/"}}