{"data":{"article":{"id":"df094608-f958-5bcd-b406-ea359067fbd8","frontmatter":{"category":"Coding","title":"PostgreSQL 12 - a precious release","date":"2019-10-29","summary":"Improved Common Table Expressions in recent release of Postgres","thumbnail":{"relativePath":"pages/postgres12-a-precious-release/elephant_cropped.jpg","childImageSharp":{"resolutions":{"base64":"data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAWABQDASIAAhEBAxEB/8QAGQABAQADAQAAAAAAAAAAAAAAAAMBAgQF/8QAFgEBAQEAAAAAAAAAAAAAAAAAAQIA/9oADAMBAAIQAxAAAAHuzwyh9NJUx1M1Cf/EABoQAAIDAQEAAAAAAAAAAAAAAAEDABESAhD/2gAIAQEAAQUC9ZwwnDAsaq5ZgM//xAAYEQADAQEAAAAAAAAAAAAAAAAAARICE//aAAgBAwEBPwGDmxaZbP/EABcRAAMBAAAAAAAAAAAAAAAAAAACEwH/2gAIAQIBAT8BoVU1MJqf/8QAGxAAAgEFAAAAAAAAAAAAAAAAADEBECAhQWH/2gAIAQEABj8CrPIwNM1Z/8QAHBABAAICAwEAAAAAAAAAAAAAAQARITEQQVFx/9oACAEBAAE/IVDbLPeEWs5BNbatDthqyfsUeMAiBon/2gAMAwEAAgADAAAAEL/Xfv/EABkRAQEAAwEAAAAAAAAAAAAAAAEAMUFRYf/aAAgBAwEBPxAOy4kkzet//8QAGREAAwADAAAAAAAAAAAAAAAAAAExEVFh/9oACAECAQE/EHnGb2IuHE//xAAdEAEAAgICAwAAAAAAAAAAAAABABEhMRBRYXGh/9oACAEBAAE/EFAAVogmhwCxZXVnre/cLABvFBlrzTMCB1e/kSbKO4RYmd3m4ZIf/9k=","width":292,"height":325,"src":"/static/5076cf686ef8d2a21a3a6da9bf016970/a2998/elephant_cropped.jpg","srcSet":"/static/5076cf686ef8d2a21a3a6da9bf016970/a2998/elephant_cropped.jpg 1x,\n/static/5076cf686ef8d2a21a3a6da9bf016970/99cce/elephant_cropped.jpg 1.5x,\n/static/5076cf686ef8d2a21a3a6da9bf016970/6e995/elephant_cropped.jpg 2x,\n/static/5076cf686ef8d2a21a3a6da9bf016970/968b1/elephant_cropped.jpg 3x"}}},"authorName":"Mariusz Nowak","authorDescription":"Mariusz is a Senior Software Engineer at AUTO1 Group.","authorAvatar":null,"headerImage":null},"html":"<p>The PostgreSQL team <a href=\"https://www.postgresql.org/about/news/1976/\">announced recently</a> a new release of the most advanced\nopen source relational database - PostgreSQL 12. As usual it comes with an impressive list of improvements\n(generated columns ♥️), one of them being long awaited by dozens of developers: <strong>improved Common Table Expressions</strong>.</p>\n<p>I should first explain what are the Common Table Expressions for those who are unfamiliar with them:\nthe CTE’s, often called <code class=\"language-text\">“WITH queries”</code>, are SQL constructs giving a possibility of creating <strong>temporal data views</strong> for a sake of a query execution.</p>\n<p>Essentially CTE is an additional query which results can be referenced in the subsequent CTE’s or the main query before which\nit is being placed. It should be clear enough with an example - here’s a sample query with two CTE’s taken from Postgres docs:</p>\n<div class=\"gatsby-highlight\" data-language=\"sql\"><pre class=\"language-sql\"><code class=\"language-sql\"><span class=\"token keyword\">WITH</span> regional_sales <span class=\"token keyword\">AS</span> <span class=\"token punctuation\">(</span>\n    <span class=\"token keyword\">SELECT</span> region<span class=\"token punctuation\">,</span> <span class=\"token function\">SUM</span><span class=\"token punctuation\">(</span>amount<span class=\"token punctuation\">)</span> <span class=\"token keyword\">AS</span> total_sales\n    <span class=\"token keyword\">FROM</span> orders\n    <span class=\"token keyword\">GROUP</span> <span class=\"token keyword\">BY</span> region\n<span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span> top_regions <span class=\"token keyword\">AS</span> <span class=\"token punctuation\">(</span>\n    <span class=\"token keyword\">SELECT</span> region\n    <span class=\"token keyword\">FROM</span> regional_sales\n    <span class=\"token keyword\">WHERE</span> total_sales <span class=\"token operator\">></span> <span class=\"token punctuation\">(</span><span class=\"token keyword\">SELECT</span> <span class=\"token function\">SUM</span><span class=\"token punctuation\">(</span>total_sales<span class=\"token punctuation\">)</span><span class=\"token operator\">/</span><span class=\"token number\">10</span> <span class=\"token keyword\">FROM</span> regional_sales<span class=\"token punctuation\">)</span>\n<span class=\"token punctuation\">)</span>\n<span class=\"token keyword\">SELECT</span> region<span class=\"token punctuation\">,</span>\n       product<span class=\"token punctuation\">,</span>\n       <span class=\"token function\">SUM</span><span class=\"token punctuation\">(</span>quantity<span class=\"token punctuation\">)</span> <span class=\"token keyword\">AS</span> product_units<span class=\"token punctuation\">,</span>\n       <span class=\"token function\">SUM</span><span class=\"token punctuation\">(</span>amount<span class=\"token punctuation\">)</span> <span class=\"token keyword\">AS</span> product_sales\n<span class=\"token keyword\">FROM</span> orders\n<span class=\"token keyword\">WHERE</span> region <span class=\"token operator\">IN</span> <span class=\"token punctuation\">(</span><span class=\"token keyword\">SELECT</span> region <span class=\"token keyword\">FROM</span> top_regions<span class=\"token punctuation\">)</span>\n<span class=\"token keyword\">GROUP</span> <span class=\"token keyword\">BY</span> region<span class=\"token punctuation\">,</span> product<span class=\"token punctuation\">;</span></code></pre></div>\n<p>Now we know what they are, but what purpose can they serve us? Well - we could parry here and say: for the same purpose as ordinary database views serve.\nThat’s of course a dramatic simplification - CTE’s are much more powerful and should not be treated as a simple database views.\nNevertheless I would like to keep the collation for the sake of this article.</p>\n<p>Database views are absolutely optional - one can simply substitute them with a subquery and achieve identical results.\nIndeed that’s what modern database engines do these days - once a database view is being used they inline it’s query as a subquery.\nWhy to bother then? We are able to deal completely without database views and even if we did use one the database engine would get rid of it anyway.</p>\n<p>What benefits do views give us then? And why the heck are they inlined?</p>\n<h3>The beauty of database views</h3>\n<p>The most appropriate explanation here is that database views help us achieve better readability.\nThey offer an elegant way of abstracting some parts of a database into a meaningful object, often matching closely with the domain.</p>\n<p>Instead of creating giant and ugly looking queries it is possible to extract some of its parts into an appealing view which is easier to browse and select data from. <strong>\"Divide and conquer\"</strong> rule in it’s true form.</p>\n<p>Still, we didn’t answer the fact that the underlying view’s query is most of the times <strong>inlined</strong> while it is being referenced. The reason is <strong>performance</strong> of course. Smart guys found out that lazy evaluation helps the optimizer a lot - by delaying the execution we could take advantage of a context of the actual query.</p>\n<p>This in turn allows many clever optimization techniques, like: pushing down predicates (<em>WHERE filters</em>), eliminating unnecessary <em>JOINS</em>, accessing only subset of columns etc.\nIn other words - a database is smart enough to do as little work as possible when evaluating database views, in the context of the issued query.</p>\n<p>Personally I love this pattern: aggregating all the data into views and letting a database to optimize my queries - these folks are really good in it and my queries are dead simple too.</p>\n<p>I have mentioned the CTE’s at the beginning, saying they are able to create temporal data views. I still conform to the comparison with database views - they both are in many cases similar.\nThe main difference is that CTE results are temporary and are reachable only in the context of a query which CTE is being part of.</p>\n<p>It may make sense to use a CTE in a place where a regular database view is not justified (e.g. it makes sense only in the context of a query and not in the whole domain), expecting similar behavior.</p>\n<h3>An ugly brother</h3>\n<p>Besides many remarkable advantages there’s at least one disadvantage which disqualifies CTE's for most use cases - before PostgreSQL 12 it was implemented as an <strong>optimization fence</strong>. What does it mean?</p>\n<p>Easy to imagine an example with a generic data view aggregating lots of data. If the view is then used to select just few records it could mean a tremendous waste of computation, if the aggregation is executed immediately.\nInstead the aggregation should be executed only on a small subset of data, which can be deduced from the outer query.</p>\n<p>Unfortunately such counter intuitive behavior was true for CTE’s for a long time - their results were <strong>materialized</strong> only to be accessible for the rest of the query afterwards.</p>\n<p>Not to blame anybody - the creators had quite good reasons to implement such behavior (i.e. guarantee of exactly one evaluation, possibility of a recursive CTE’s and more) but this still feels like focusing on corner cases instead of optimizing the happy path.\nThat’s why the community <a href=\"https://www.postgresql.org/message-id/flat/201209191305.44674.db%40kavod.com\">insisted for a long time</a> for changing the status quo by giving the possibility of disabling the fence and unlocking the full potential of CTE’s.</p>\n<h3>Game changer</h3>\n<p>The SQL gods listen to their prayers and here it is - PostgreSQL 12 with updated <a href=\"https://www.postgresql.org/docs/12/queries-with.html\">Common Table Expressions</a>.\nBy default, when few constraints are met, the queries will be inlined allowing joint optimizations.</p>\n<p>It is still possible to force the old behavior - by defining the CTE <code class=\"language-text\">AS MATERIALIZED</code> the engine would execute it immediately.\nIt is also possible to hint the optimizer that we definitely want the CTE to be inlined, e.g. when the CTE is being referenced twice the engine won't inline it by default.</p>\n<p>This is truly a game changer for many developers who care about their queries’ readability, allowing them to substitute not very well liked subqueries with elegant <code class=\"language-text\">“WITH queries”</code>.</p>\n<p>Don’t get me wrong - not every subquery should be immediately replaced, they still have their strengths and in some cases they should be chosen over CTE’s. It is just convenient to have two distinct tools in a toolbox, isn’t it?</p>","fields":{"slug":"/postgres12-a-precious-release/","tags":["postgres","postgres12","release","sql","cte"]}},"categoryArticles":{"edges":[{"node":{"id":"f3a0fb4b-eb2f-5624-a408-d63e3cee5184","frontmatter":{"category":"Coding","title":"Spring batch integration","date":"2020-02-07","summary":"Usage cases for spring-batch.","thumbnail":null,"authorName":"Artur Yolchyan","authorDescription":"Artur is a Senior Software Engineer at AUTO1 Group.","authorAvatar":{"relativePath":"pages/spring-batch-integration/avatar.png","childImageSharp":{"resolutions":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAIAAAAC64paAAAACXBIWXMAAAsSAAALEgHS3X78AAAEfElEQVQ4yz2O2VMbBQDGlzJQSylXIEc3F0eODYGEJAQI5GBzbK49kt0cm703CSRQqfQCB9taap1qgY61VXqoPZxxbKe2dWo7tY6d0RdHX/0HfPLRF991qTPO/OZ7+33fB+RDFjruKMWhcgwqwnYqaiVhKwXbiolRgZiuVxJ1LrsgEg25sFilFqrFBblQFXNVgajyBMCkxiuIs4yMMoiDSTiwoC3kc/hdVpdVPzFqRua9MpupS7mqmK9LVF0u1CVFzssCIXMYwKZcTGpMyWLUOe2yjoxAQyNO1YCutbV9f1tbe1u7dcRY47GaMiXuVVSFvMTjModLLApwaRefHqeibqNm4EBnb/+A1mo2T9kHcZ9tGR5LQocPvdFmNusEOqv8lPicxBESi4kstifzabeMuj1Wnba7i/Q71vDgJ/Xc4zXhyWrxq1pyG/eWvEMd+9umfWMLAiFWshKD/g8goROV5LjdBJa9ls9r2edr4svTjRenG8836o9WK7e46EXM5zbpNGoVX0qKdEqk00qFgkBnAGrOko+Nz1jA94iZhyvFZ8fZ707JLzaWft48/vJ08/6b5Y+K4azHph5QlbCIXE7yJYRXco8U4Ffvn7ZoAiPgRSp8vU59s9Z89s7RJ2fXtxerbxGpo5nIOWxaCLr1BhOZDUqlOF+ICyVEQSwnAcuBFmtHi8ekRT0OMjBZQyI3lvgduVCLzvGx0HJi9nw+WPTbJ4dNdSLMUTBXiAnF+GsSgKN7n62zxWnQVAIuOjCxEJnaxuevleMfkMjJzPxGcuZTPs4FoA0U3uHIIhHkqKgCr1CIAx6wBeptTY3ZTiRnzmPhbTp9gyFuc+hNBnm6Kj48tXy1Ri7Brs8WxTMVvITN8fkIT8I8GRXIKFCAR11g1wSo3WSIb9dXbojEnUb1C5m5XkJ+ePvI4/WVHSm3BE98SKNCZpbBg6xyntzz92QxN+U39XYBQDMdfbTWvCpiF/Kpyyy1Wy/fapS+XC5tcclq0JGdMOViHhYP/Sdzyn5+HuBR3+xwXwcABG1DNxvkOgqfLxR3q4vvoujFQvzeSuGymKV8w5C+m4p7GTTIYEE2F+b2iABcZnLW2tsNAPrOg5f4zJVyYgfH7vHibY76epm8eyR/BpuU0inPNBFwW6RcSPGVfQYPcbl5gM14Ex69/gDQvW8f7rHuyujtGnm3yT84Id45Sp8lw0dwZHPrqX0s3N/Xnwl56UyAI0KvCQN02lOIOcfV7erWFvBgOwwZj+VSm0LleDlfR+aOsfSDV3+yS1udHV2aAZNaBQ4aByddTjQ6VcGCAJv1wX472K9S96gOHeyZmkHoWJiJ+Jsxz9ax1Ve//33p3k86tVmnM2s0JgWtdlCrHdKDw5AVAoio+7DW2NOj6+lRazQj71/99crayY8b+P3rd3/5459Hv/017o7otENGo82gt5jNo0rq9cMGg0UPWoBZj7O3Dxzo1/f1alyT6OL645Xm2cvXflw+93Rz93tx6YJaZRocHDMYIKMRAg9bQHDYZIIMBrvZ7PwXcPlkRtKKCQsAAAAASUVORK5CYII=","width":50,"height":50,"src":"/static/dc9516b9327e627890a1f5c7f84c004a/45876/avatar.png","srcSet":"/static/dc9516b9327e627890a1f5c7f84c004a/45876/avatar.png 1x,\n/static/dc9516b9327e627890a1f5c7f84c004a/eb85b/avatar.png 1.5x,\n/static/dc9516b9327e627890a1f5c7f84c004a/4f71c/avatar.png 2x,\n/static/dc9516b9327e627890a1f5c7f84c004a/9ec3e/avatar.png 3x"}}},"headerImage":null},"html":"<p><strong>Intro</strong></p>\n<p>In this article, we will take a look at spring-batch and how it could be used. We will walk through various configurations and we will create an application which reads from a CSV file &#x26; writes into a database with outstanding performance.</p>\n<p>I used the following: Java 11, Spring 5+, Spring Boot 2 and Maven-based project.</p>\n<p><strong>Create a Project</strong></p>\n<p>First, we need to create a Spring Boot 2 project. We recommend that you do so by visiting <a href=\"https://start.spring.io/\">spring initializer</a>, which is a useful tool to generate spring projects with required dependencies and configurations.</p>\n<p><strong>Dependencies</strong></p>\n<p>We need the dependencies below to run and test the project:</p>\n<div class=\"gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">&lt;dependency> \n &lt;groupId>org.springframework.boot&lt;/groupId>\n &lt;artifactId>spring-boot-starter&lt;/artifactId>\n&lt;/dependency>\n   \n&lt;dependency>\n &lt;groupId>org.springframework.boot&lt;/groupId>\n &lt;artifactId>spring-boot-starter-test&lt;/artifactId>\n &lt;scope>test&lt;/scope>\n &lt;exclusions>\n    &lt;exclusion>\n     &lt;groupId>org.junit.vintage&lt;/groupId>\n      &lt;artifactId>junit-vintage-engine&lt;/artifactId>\n    &lt;/exclusion>\n &lt;/exclusions>\n&lt;/dependency>\n\n&lt;dependency>\n &lt;groupId>org.springframework.boot&lt;/groupId>\n &lt;artifactId>spring-boot-starter-batch&lt;/artifactId>\n&lt;/dependency>\n\n&lt;dependency>\n &lt;groupId>org.springframework.boot&lt;/groupId>\n &lt;artifactId>spring-boot-starter-data-jpa&lt;/artifactId>\n&lt;/dependency>    \n\n&lt;dependency>\n &lt;groupId>org.projectlombok&lt;/groupId>\n &lt;artifactId>lombok&lt;/artifactId>\n &lt;version>1.18.10&lt;/version>\n &lt;scope>provided&lt;/scope>\n&lt;/dependency>\n\n&lt;dependency>\n &lt;groupId>com.h2database&lt;/groupId>\n &lt;artifactId>h2&lt;/artifactId>\n&lt;/dependency>\n    \n&lt;dependency>\n &lt;groupId>org.springframework.boot&lt;/groupId>\n &lt;artifactId>spring-boot-starter-test&lt;/artifactId>\n &lt;scope>test&lt;/scope>\n &lt;exclusions>\n     &lt;exclusion>\n     &lt;groupId>org.junit.vintage&lt;/groupId>\n     &lt;artifactId>junit-vintage-engine&lt;/artifactId>\n     &lt;/exclusion>\n &lt;/exclusions>\n&lt;/dependency>\n\n&lt;dependency>\n &lt;groupId>org.springframework.batch&lt;/groupId>\n &lt;artifactId>spring-batch-test&lt;/artifactId>\n &lt;scope>test&lt;/scope>\n&lt;/dependency>\n\n&lt;dependency>\n &lt;groupId>org.hamcrest&lt;/groupId>\n &lt;artifactId>hamcrest-all&lt;/artifactId>\n &lt;version>1.3&lt;/version>\n &lt;scope>test&lt;/scope>\n&lt;/dependency></code></pre></div>\n<p><em>spring-boot-starter-batch</em> dependency includes all the configurations to run the spring batch application. <a href=\"https://projectlombok.org/\">Lombok</a>  is just a helper dependency to write the code faster and cleaner. <a href=\"http://www.h2database.com/\">H2</a>  is used as an in-memory database. <em>spring-boot-starter-test</em> and <em>spring-batch-test</em> are included for test purposes.</p>\n<p><strong>Book Class</strong></p>\n<p>Let’s create a model class book, which will represent a book. This will just serve as a model class and will help us during implementation of spring batch.</p>\n<div class=\"gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">@Data\n\npublic class Book {\nprivate String title;\nprivate String description;\nprivate String author;\n}</code></pre></div>\n<p><strong>Configuration</strong></p>\n<p>Let’s create a class called SpringBatchConfiguration. We will add all required configurations here. First, let’s annotate this class with <a href=\"https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/context/annotation/Configuration.html\">@Configuration</a> to be able to inject beans, and with <a href=\"https://docs.spring.io/spring-batch/docs/current/api/org/springframework/batch/core/configuration/annotation/EnableBatchProcessing.html\">@EnableBatchProcessing</a> to enable spring batch processing. Additionally, we can add <a href=\"https://projectlombok.org/features/constructor\">@RequiredArgsConstructor</a> from Lombok which would help us to generate constructor with parameters. These parameters are the ones which are marked as final class properties. These properties will be injected as spring beans. Our class will be like this:</p>\n<div class=\"gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">@Configuration\n@EnableBatchProcessing\n@RequiredArgsConstructor\npublic class SpringBatchConfiguration</code></pre></div>\n<p>Now, in SpringBatchConfiguration class let’s add properties which need to be injected into the constructor:</p>\n<div class=\"gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">private final JobBuilderFactory jobBuilderFactory;\nprivate final StepBuilderFactory stepBuilderFactory;</code></pre></div>\n<p><em>jobBuilderFactory</em> and <em>stepBuilderFactory</em> are declared in spring batch jar as spring beans so that we can inject them in any class we want.</p>\n<p><strong>File Reader</strong></p>\n<p>Now, we need to declare and initialize spring beans to configure the batch process. The first bean which we will need will be responsible for reading from a file line by line. Spring Batch provides a default class for it. The class name is <em>FlatFileItemReader</em>. Similarly, spring has different default reader classes for reading from a relational database, mongodb and etc. However, if you need, you can create your own reader and implement it in a way you want.</p>\n<p>Let’s now see what <em>FlatFileItemReader</em> injection will look like.</p>\n<div class=\"gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">@Bean\n@StepScope\npublic FlatFileItemReader&lt;Book> bookReader(@Value(\"#{jobParameters['filePath']}\") final String filePath\n) {\nreturn new FlatFileItemReaderBuilder&lt;Book>()\n    .name(\"personItemReader\")\n    .resource(new ClassPathResource(filePath))\n    .delimited()\n    .names(new String[]{\"title\", \"description\", \"author\"})\n    .fieldSetMapper(new BeanWrapperFieldSetMapper&lt;Book>() {{\n    setTargetType(Book.class);\n    }})\n    .build();\n}</code></pre></div>\n<p>We are configuring that the bean reader should read data from the given file path, which should be a CSV file having rows with title, description and author respectively.</p>\n<p>The <a href=\"https://docs.spring.io/spring-batch/docs/current/api/org/springframework/batch/core/scope/StepScope.html\">StepScope</a> means to initialize this bean after each step, so file path could be dynamically set when the spring batch job is launched. We will come to that later, how to pass the file path later in this article.</p>\n<p><strong>Item Writer</strong></p>\n<p>Now, let’s create a writer class, which will take the data and write into the relational database.</p>\n<div class=\"gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">@Bean\npublic JdbcBatchItemWriter&lt;Book> writer(final DataSource dataSource) {\n    return new JdbcBatchItemWriterBuilder&lt;Book>()\n        .itemPreparedStatementSetter((book, preparedStatement) -> {\n            preparedStatement.setString(1, book.getTitle());\n            preparedStatement.setString(2, book.getDescription());\n            preparedStatement.setString(3, book.getAuthor());\n        })\n        .sql(\"INSERT INTO books (title, description, author) VALUES (title, description, author_surname)\")\n        .dataSource(dataSource)\n        .build();\n} </code></pre></div>\n<p>In the writer bean, we are setting item processors and adding values inside <em>preparedStatement</em> accordingly, which book property should be inserted for each db table column.  </p>\n<p><strong>Step Configuration</strong></p>\n<p>Now, let’s configure a step which will be executed in the batch process. In our case, the configuration will look like this:</p>\n<div class=\"gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">@Bean\npublic Step step1(final ItemWriter&lt;Book> writer, final ItemReader&lt;Book> reader) {\n    return stepBuilderFactory.get(\"step1\")\n        .&lt;Book, Book> chunk(100)\n        .reader(reader)\n        .processor((ItemProcessor&lt;Book, Book>) book -> book)\n        .writer(writer)\n        .build();\n}</code></pre></div>\n<p>In our scenario, we have only one step, but it's also possible to configure multiple steps. Here, we are creating a spring batch step with the name <em>step1</em> and setting reader and writer accordingly. These are the readers and writers which we created as spring beans earlier.</p>\n<p>We are setting chunk as 100, which means the items chunk proceeded is 100. We can make this configurable too. The processor is for converting the current object to the one which the writer should proceed with. In our case, it is the same object.</p>\n<p><strong>Job Configuration</strong></p>\n<p>Last but not least, let’s configure the job which should be executed.</p>\n<div class=\"gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">@Bean\npublic Job importUserJob(final Step step1) {\n    return jobBuilderFactory.get(\"bookReaderJob\")\n        .incrementer(new RunIdIncrementer())\n        .flow(step1)\n        .end()\n        .build();\n}</code></pre></div>\n<p>Here, we create a job with the name <em>bookReaderJob</em>. We add an incrementer <a href=\"https://docs.spring.io/spring-batch/docs/current/api/org/springframework/batch/core/launch/support/RunIdIncrementer.html\">RunIdIncrementer</a>, which is an id generator for the tables which are specifically designed to store the details about job executions in the database. After each time the spring batch job is executed, it will save details about the execution. To check the schema structure for storing this data, take a look at <a href=\"https://github.com/spring-projects/spring-batch/blob/master/spring-batch-core/src/main/resources/org/springframework/batch/core/schema-mysql.sql\">this sql</a>. It is for MySql, but other SQL scripts are available too.</p>\n<p>Additionally, we add flow by which the job should be executed. Currently, we have only one step in our flow, so we add it.  </p>\n<p>Please also add this config: <code class=\"language-text\">spring.batch.job.enabled=false</code> in your properties config file so that spring batch job won’t be executed automatically with no parameters when the application is started.</p>\n<p><strong>Execution</strong></p>\n<p>To execute the job, we need to declare <a href=\"https://docs.spring.io/spring-batch/docs/current/api/org/springframework/batch/core/launch/JobLauncher.html\">JobLauncher</a> and launch the job. To do so, we need to create the below class:</p>\n<div class=\"gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">@Component\n@RequiredArgsConstructor\npublic class SpringBatchExecutor {  \n    private final JobLauncher jobLauncher;\n    private final Job job;  \n\n    @SneakyThrows\n    public void execute(final String filePath) {\n        JobParameters parameters = new JobParametersBuilder()\n            .addString(\"filePath\", filePath)\n            .toJobParameters();  \n        jobLauncher.run(job, parameters);\n    }  \n}</code></pre></div>\n<p>Now, we can call the execute method from whenever we want, with the file path from which the data should be read.</p>\n<p><strong>Additional Classes</strong></p>\n<p>There are a few additional classes which you will need to execute your code.</p>\n<p>Create a class <em>BookEntity</em> so that spring data JPA will automatically create the book table for you. Then you can create repository.</p>\n<div class=\"gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">@Data\n@Entity\n@Table(name = \"books\")\npublic class BookEntity {\n    @Id\n    @GeneratedValue(strategy = GenerationType.IDENTITY)\n    private Long id;\n    private String title;\n    private String description;\n    private String authorFullName;\n}</code></pre></div>\n<p>Then create the interface <em>BookRepository</em> and extend it from <em>JpaRepository</em>. At the moment, we will need this only for testing.  </p>\n<div class=\"gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">@Repository\npublic interface BookRepository extends JpaRepository&lt;BookEntity, Long> {\n} </code></pre></div>\n<p><strong>Testing</strong></p>\n<p>No one likes a code which is not tested. So, let’s write a few test cases for our class.</p>\n<p>Here is a code sample for test cases:</p>\n<div class=\"gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">@Slf4j\n\n@SpringBootTest\nclass SpringBatchSampleApplicationIntegrationTest {\n\n    @Autowired\n    private SpringBatchExecutor springBatchExecutor;\n    \n    @Autowired\n    private BookRepository bookRepository;\n\n    @Test\n    public void testExecution() {\n        long initialCount = bookRepository.count();\n        assertThat(initialCount, equalTo(0L));\n        springBatchExecutor.execute(\"sample-data.csv\");\n        long count = bookRepository.count();\n        assertThat(count, equalTo(7L));\n    } \n\n    @Test\n    public void testLargeData() {\n        long startTime = System.currentTimeMillis();\n        long initialCount = bookRepository.count();\n        assertThat(initialCount, equalTo(0L));\n        springBatchExecutor.execute(\"large-data.csv\");\n        long count = bookRepository.count();\n        assertThat(count, equalTo(60000L));\n        long endTime = System.currentTimeMillis();\n        log.info(\"executed in miles: {}\", endTime - startTime);\n    }\n}</code></pre></div>\n<p>The second test executes in ≈ <strong>3500 ms</strong> in a machine with a 2.2 Ghz Intel Core i7 and 16GB ram. It proceeds 60K lines of CSV file, and saves it into a relational database.</p>\n<p>You can check out the working sample code in <a href=\"https://github.com/yolch-yolchyan/spring-batch-sample\">github</a>,</p>","fields":{"slug":"/spring-batch-integration/","tags":["auto1","engineering","spring","code","java"]}}},{"node":{"id":"a3a21c38-873e-56db-a170-eec0e6136040","frontmatter":{"category":"Coding","title":"Writing IntelliJ plugins","date":"2019-12-10","summary":"How to write a simple IntelliJ plugin","thumbnail":{"relativePath":"pages/intellij-plugin/logo.png","childImageSharp":{"resolutions":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAACXBIWXMAAAsSAAALEgHS3X78AAAEyElEQVQ4y3WVe0xTVxzHz723rfZBsVeqnc4Yw0aYFSiFFZlZxnSo4w+gSBWEglTmA59jCt4WCOUxq+J4zGwaMqfJfDBi2GbMxjJfMXMzJks0Y5ngfE0mqAwrFLHtPb+de4CKf+wkv5zfOed3Pr/vOb+Te9FAzEokNV9cLvq/Nmpew8L8DIQOANJUPEdh+wGpBB8jrSldo0hd7n0RLJry0fA4bCg2RxYw5S3zm/ISnsWt1vvi8qZMxD1KLkVvb+lmJifS7hrmpJ4lCfidAy8WAqZ8dqzPSwFzIQRN+UEy95SMbxK7MhK3umQiVlnuLVQKwxcVW//SS2O94JNFFZyja3NLHyD03JSHIN5OMxHQZ5C4Fgg0CAlFAIkOAMs6gIWbiV9sQ0cgTlMl+tW7ATSV+E64y2+R9kWVDXJR226PZZSAUvPG5mpxvP0+MfjjjfTg9eh0/Nv8TPGXBdmBS3H5cC52tS8253SffNMN0BZfHdVu7AK+tC9gIIon1MdsvkXvkKojd2aT1N02ZgXDWBnmGBbLJWM5IL4oZzhQEEOMTESsHBBiAjNzz8BrVSJEb721b3taOzdWlIQien+kECfB8gHciM8NkCHOyLLC711d+MPSUkzGIM159njE5IVJ1CfVgXnZbeKbpQ9Ey84+iCy7kxUqylB8QeQoUTeatAWumteIMhKs43m42dMDFotFAgDDMHD+/HlIT88YA7IsNmUcwWmbb4hRu+4BX9mfGQI+SSiY/SBxneeflJLHZ5NKQM7IqKofOzth1qxZMK4QOjo6CDCd+izLwNLlLXhh+R2sr3oEM4SHy8bUOYz07H0daFrQNWPw57XJQG8iIQEwxmC1WiE1NRWampqgu7sbzGYzBUqniLV9gee4B3GE6zHonAMpFAh7ZPSx+sqmH4Pa6XB5++vSHcJbixbhpsZGSEtLA6PRCK2trZCTkxNSK5m+oB2/4h6WYDjcOZgcOvLDHbxyZJfuT6ifDhc3zA8qZIqXNr5sTMiPsJ/CevcoEFgwzPnETGHPBB1VeG+TwQDV2rNnC98FBmlEhUKG1So1TJ06FeRyOchkMuA47iWgzv4t5msCQGB+ldNrDCns3b6AQgGOs42LS67PnR0J+z9pCDY3N+ODhw7i9RvW08qOW8jX2k/jaTUY1M6nI0rhaSSF9e2IRlXvXKD+paJrEbVL9varp6hBGx7m53lejNDxYrhKE6TKGAYj8tiJT4Ea+5mA1o1B5Rz2KwXvnJDClszDtNKfWw9bW7KOwrYl9bAltQGKF3sgb/k+WJpzAGIcXwYiHV/j2Y7vxAjHD4FwxznQurygqQdQunw9yrIBLYV5rEdRQ/YJCty74qujhwp/gt253/R/bP/+eJPj8vvr3JdWvld95X6Spxeiq//Gc2uegMEDoHP7Iaxy5ILKOVREjjtN2k+UIlS34hgF12UeVtRln/i02ta2aWN6q37ydy9mfQdvFK61zqu4CwZnbx8v9Ddrd95PnBxDVI455dknaE9A7OSA+lWn2Orsdi7zo05uYu5V513LTKHXMDHW12Gkcvk4pTBEi6qegLptJ2nfU9CJam1tXKWtjRFWtSND1S06b3H+yiRWXg8l1Ff8y5G3x6oELyJK0cwa6TfwmK79B0KrRX19cxThAAAAAElFTkSuQmCC","width":325,"height":325,"src":"/static/b2f976ed5fa752977d8f8f9b2516534c/b3029/logo.png","srcSet":"/static/b2f976ed5fa752977d8f8f9b2516534c/b3029/logo.png 1x,\n/static/b2f976ed5fa752977d8f8f9b2516534c/8d141/logo.png 1.5x,\n/static/b2f976ed5fa752977d8f8f9b2516534c/ee72c/logo.png 2x,\n/static/b2f976ed5fa752977d8f8f9b2516534c/5dfa8/logo.png 3x"}}},"authorName":"Piotr Czekaj","authorDescription":"Piotr is a Senior Software Engineer at AUTO1 Group.","authorAvatar":{"relativePath":"pages/intellij-plugin/avatar.png","childImageSharp":{"resolutions":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAACXBIWXMAAAsSAAALEgHS3X78AAACyElEQVQ4y4VUO2gUURR9mZmN8YcItoKVjeXuzsxu9jOzm92NkBBTqDEmjZAEgtqIpSgI1gp+uhS6kEI7wc7GQsFCLERiISGCaGHhF02yu+M5s/cujyC4cJY379573r3n3XdNvV51xsYiJ4rKbqlUyBj8wjAYyWazp4BVYB3YAraBDeAhMBcE/l76lkrFTLVachuNyCGXEbJMrVbx6ADnaWAtn88nvu8nWBMdQcJ9Auv3wCxjWq2aC9IMSF3DzCyyG1YAs9pSYkL2melmLpfT71tKGkUlz2iZJAuCgA5dEjGAwPoV0AbuAy+tfR7YkZjb5CiXR1OutEw5jWQdCfgCnEiSxNg/7LWAj+KTSiHSzBvrAtascrriPCmnDkP4AYQ0Em3TGPHf8P38ARpP/4PsHQ7aU69Hqdi4OJeI47JXLg9IX1tVbUuWCzSsygcJO+L0goGNRpySoB1colarerhEvcCn4tuxCB/TsC5ZdS3Ct2Ho75uZmRoigWbIbgCxt7Q0O8TLsgg17o2R2+JHzzJcV/1IoBlybel42SLsCcc3I6UqoaZ+lUHFYjjCzJSQa+4J4UVLKiX8ScOGVXJXDN+xd7SfZXFYS65U+n2Wz+cOw+ezHadSkfCRdVJiZdlmMG9ZtHMpgWR3Z0eMSvWExjmrbXoCbZ951dIim7Yk6u1IYtlwavChW51Pp01tXOwf01eC9RHs/Rbbnx2Hf4IUh/Q5zdol8H3KG22Pj9edOK54LF1876pd37TELhqdZ+J4MwxDHUvXgDOFQrB7YqLpjI4WdhG8GLYNbCeBK/1+TWNWRG+Pfy5Hj5Dek3IXzX9+8DkL/AIeLC/PDU1NHXdSQk5altNsDkjPAT+ArzKyFnK5bB2IxbYik4hanmfM5GTL6Q/Y2DUc25y0HLToubR8TI39cL4APJOxr/35AXgOXEJnHKQvepP6eiQj119kDrZjqLo8HAAAAABJRU5ErkJggg==","width":50,"height":50,"src":"/static/26a7a327ccc4b335712e5a7086f2b26d/45876/avatar.png","srcSet":"/static/26a7a327ccc4b335712e5a7086f2b26d/45876/avatar.png 1x,\n/static/26a7a327ccc4b335712e5a7086f2b26d/eb85b/avatar.png 1.5x,\n/static/26a7a327ccc4b335712e5a7086f2b26d/4f71c/avatar.png 2x,\n/static/26a7a327ccc4b335712e5a7086f2b26d/9ec3e/avatar.png 3x"}}},"headerImage":{"relativePath":"pages/intellij-plugin/header.png","childImageSharp":{"resolutions":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAYAAAB/Ca1DAAAACXBIWXMAAAsSAAALEgHS3X78AAADGklEQVQozx3R60/bVRjA8V80m2N4IVkWcfpmqyulTdd7oRYopEDbyaXlVgptobANkAzrUpwbyjZvgMpQ7CxhGCaXUTcv04mRRYMkKpB1MLYpIKkymb5S/4WvZ7745DkvnnOey5FS87qQWbqY0zWyIEzrmxkxHOFHcXZkRZCsZ0ixnmKH9TQPWV7m0eIo22q/JmjvI6ENsijyh7I62G7rYXt2F1KgpIo2TZhlbYBFkTCjDaE2Rdhn6mS36TiPC+nml9ilP0a6rQ91wxwZhxJ4ar9kMbuDdeMR+h0DyAOzyBwxpJDhMCsHAlzXBFgQ7mj8DGqaeUr3Agrt8yh0YWQiZolOq9wTuLxXcFZ/SmHNFVrKL/DKwXMcrPkcu2+aYkGKqkKsquu5rvZzQ7gf19R1nFTUo1M0Y5E3YNWGidu6mSzsQdc0j+ZwgrzgLFUVcWEKn/uiMInfPY40pPKxrvWypPFyU7ilqWZJX8dr9l4UrjFUzlFy3OJS8BqWtmVkRzeQtf/K3qNJCsT4EWeUU65+ely9HHOdQ3pR4Wa1OI8Vez637DaWiwp5tfxtIidmGbywxsilJH2xn3lneI3RyXU+iK3Q1votPu9VfP5vOOGMEbeHmXEcoregV+wwvYx4volk816SoSeZrS3lfPmbfFj2OqPeQcbqo4z7+pnwDvBxYJjJ2iFGSt8j5jhLzPUuY7ndXLREmMruZMJyHCmyq4jO3UWMGg1MO+XM5z7LkiHEDwcamVM28JM6wFpODas5Xm7omljRt3DH1Mptcxu/GFv4yNlNZ3CQPk8P14ytSG+l5XHmESund+ZzcmcuX+xx8ldmNckMD78pKthUevjHXMK/5lLuZlYIlWwpq9lSVJJUeQkFL2N77ntsHfO8URpFGk41M572DLFUI++nGDj/sJnb+0q4l1nFH8LW/yrZ2O8mKfdwVxT5/X4x4c8MN+3ip1XtGxj8X+GouYw081gW9+TlfJaiY/xBJWMPKPlkh5bEEwXc3GMnkV7Ad2nZxLepuZpqYHN/GVvisU3h76dLmDKGsTQuoK+7RJNrgP8AU8rtTZmilCkAAAAASUVORK5CYII=","width":1280,"height":720,"src":"/static/6fae10ea7503a11a8f308ac2e2a5217a/26421/header.png","srcSet":"/static/6fae10ea7503a11a8f308ac2e2a5217a/26421/header.png 1x"}}}},"html":"<h2>Background</h2>\n<p>During analysis of why some services take a long time to build, several problems have been found, mostly related to number of Spring contexts that were created during integration tests. More about those problems can be found in <a href=\"https://auto1.tech/integration-test-speedup\">previous blog post</a>. In order to decrease the likelihood that slow tests will appear at AUTO1, we implemented an IntelliJ plugin which warns a developer about possible problems when he writes code and provides quick fixes if they are applicable.</p>\n<h2>Plugin inspections</h2>\n<ul>\n<li>warns about usage of <code class=\"language-text\">@DirtiesContext</code> annotation which slows tests down because it forces creation of new Spring context</li>\n<li>warns about specifying the same list of profiles but in different order in <code class=\"language-text\">@ActiveProfiles</code> (slows tests down because different Spring context would have to be created for each combination)</li>\n<li>warns if number of distinct profile combinations used in <code class=\"language-text\">@ActiveProfiles</code> is greater than 3</li>\n<li>warns if it finds <code class=\"language-text\">@FeignClient</code> (or DTO used by client) not documented with Swagger annotations</li>\n<li>warns if remote HTTP call is used inside method annotated with <code class=\"language-text\">@Transactional</code></li>\n</ul>\n<p>During the plugin development, we realized that resources on writing IntelliJ plugins are scarce, and therefore decided to create a step by step tutorial on how to implement <code class=\"language-text\">@DirtiesContext</code> inspection.</p>\n<h2>Create plugin</h2>\n<p>In our tutorial we will be using the community edition of IntelliJ 2018.3.5. Final source code is available on <a href=\"https://github.com/pczekaj/tutorial-intellij-plugin\">github</a>.\nThere are several ways on how to create IntelliJ plugin. The recommended one is to use Intellij plugin for Gradle and that’s what we will use in this tutorial. Let’s start with creating new project using <em>File > New > Project...</em>, select Gradle and make sure that in <em>Additional Libraries and Frameworks</em> both <em>Java</em> and <em>Intellij Platform Plugin</em> are selected.\nIf you cannot see “Gradle” or “Intellij Platform Plugin” then please make sure that both “Gradle” and “Plugin DevKit” IntelliJ plugins are installed.\nContinue next steps of the wizard using default values, use any groupId and artifactId. After some time IntelliJ will download dependencies and create an empty plugin.</p>\n<h2>Inspection</h2>\n<p>Our inspection should warn a developer each time there is a class annotated with <code class=\"language-text\">org.springframework.test.annotation.DirtiesContext</code> and provide quick fix which deletes <code class=\"language-text\">@DirtiesContext</code>. If Spring is not your thing then any other annotation can be used instead.</p>\n<p>There are two kinds of inspections:</p>\n<p>Local inspections are executed in the background when file is opened, in general they have access to currently open file. Local inspection cannot report problem for not currently processed file. Inspection class has to extend <code class=\"language-text\">com.intellij.codeInspection.LocalInspectionTool</code> or one of subclasses.\nGlobal inspections work only in batch mode when analysis is manually triggered via <em>Analyze > Inspect Code</em> and see complete graph of references between classes and can report problem for any file. Inspection class has to extend <code class=\"language-text\">com.intellij.codeInspection.GlobalInspectionTool</code> or one of subclasses.</p>\n<p>We don’t need to access complete graph of references and we would like to give a hint that something is wrong as soon as possible so local inspection is a better choice for our use case. First problem that we encounter is to pick proper base class. One approach is to ask IntelliJ to show class Hierarchy of <code class=\"language-text\">LocalInspectionTool</code> and take a look what other inspections are extending. In this case <code class=\"language-text\">AbstractBaseJavaLocalInspectionTool</code> seems to be a good choice since most of Java inspections are based on it.</p>\n<p>Create new class named <code class=\"language-text\">DirtiesContextInspection</code> with following content:</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\">DirtiesContextFirstVersionInspection</span> <span class=\"token keyword\">extends</span> <span class=\"token class-name\">AbstractBaseJavaLocalInspectionTool</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token keyword\">private</span> <span class=\"token keyword\">static</span> <span class=\"token keyword\">final</span> <span class=\"token class-name\">String</span> DIRTIES_CONTEXT <span class=\"token operator\">=</span> <span class=\"token string\">\"org.springframework.test.annotation.DirtiesContext\"</span><span class=\"token punctuation\">;</span>\n\n    <span class=\"token keyword\">private</span> <span class=\"token keyword\">static</span> <span class=\"token keyword\">final</span> <span class=\"token class-name\">String</span> DESCRIPTION_TEMPLATE <span class=\"token operator\">=</span> <span class=\"token string\">\"Usage of @DirtiesContext makes integration tests slower\"</span><span class=\"token punctuation\">;</span>\n\n    <span class=\"token keyword\">public</span> <span class=\"token class-name\">String</span> <span class=\"token function\">getDisplayName</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 string\">\"Usage of @DirtiesContext is not recommended\"</span><span class=\"token punctuation\">;</span>\n    <span class=\"token punctuation\">}</span>\n\n    <span class=\"token keyword\">public</span> <span class=\"token class-name\">String</span> <span class=\"token function\">getGroupDisplayName</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 class-name\">GroupNames</span><span class=\"token punctuation\">.</span>PERFORMANCE_GROUP_NAME<span class=\"token punctuation\">;</span>\n    <span class=\"token punctuation\">}</span>\n\n    <span class=\"token keyword\">public</span> <span class=\"token class-name\">String</span> <span class=\"token function\">getShortName</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 string\">\"DirtiesContext\"</span><span class=\"token punctuation\">;</span>\n    <span class=\"token punctuation\">}</span>\n\n    <span class=\"token keyword\">public</span> <span class=\"token keyword\">boolean</span> <span class=\"token function\">isEnabledByDefault</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\">true</span><span class=\"token punctuation\">;</span>\n    <span class=\"token punctuation\">}</span>\n\n    <span class=\"token keyword\">public</span> <span class=\"token class-name\">PsiElementVisitor</span> <span class=\"token function\">buildVisitor</span><span class=\"token punctuation\">(</span><span class=\"token annotation punctuation\">@NotNull</span> <span class=\"token keyword\">final</span> <span class=\"token class-name\">ProblemsHolder</span> holder<span class=\"token punctuation\">,</span> \n                                          <span class=\"token keyword\">boolean</span> isOnTheFly<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n        <span class=\"token keyword\">return</span> <span class=\"token keyword\">new</span> <span class=\"token class-name\">JavaElementVisitor</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n\n            <span class=\"token keyword\">public</span> <span class=\"token keyword\">void</span> <span class=\"token function\">visitAnnotation</span><span class=\"token punctuation\">(</span><span class=\"token class-name\">PsiAnnotation</span> annotation<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n                <span class=\"token keyword\">super</span><span class=\"token punctuation\">.</span><span class=\"token function\">visitAnnotation</span><span class=\"token punctuation\">(</span>annotation<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n\n                <span class=\"token class-name\">String</span> qualifiedName <span class=\"token operator\">=</span> annotation<span class=\"token punctuation\">.</span><span class=\"token function\">getQualifiedName</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n\n                <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span>DIRTIES_CONTEXT<span class=\"token punctuation\">.</span><span class=\"token function\">equals</span><span class=\"token punctuation\">(</span>qualifiedName<span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n                    holder<span class=\"token punctuation\">.</span><span class=\"token function\">registerProblem</span><span class=\"token punctuation\">(</span>annotation<span class=\"token punctuation\">,</span> DESCRIPTION_TEMPLATE<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n                <span class=\"token punctuation\">}</span>\n            <span class=\"token punctuation\">}</span>\n        <span class=\"token punctuation\">}</span><span class=\"token punctuation\">;</span>\n    <span class=\"token punctuation\">}</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<p>The most interesting thing happens in a visitor which is notified each time a Java annotation is encountered in source code. By overriding different methods, plugin can process methods, classes, imports etc. In our case we check if fully qualified name of annotation matches our expectations and register a problem when that’s the case. Later on we will change this class to include also a quick fix. Creation of inspection class is not enough to make it available in IntelliJ - it’s also needed to register inspection in <code class=\"language-text\">plugin.xml</code> which among other things describes what plugin does, what other plugins are required and in which version of IntelliJ it can be used.</p>\n<p>It’s possible to register each inspection one by one in <code class=\"language-text\">plugin.xml</code> under extensions tag and configure inspection using xml but we find it easier to register <code class=\"language-text\">inspectionToolProvider</code> and configure using it in Java code.</p>\n<p>Create the following class to implement our inspection provider:</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\">CodeInspectionProvider</span> <span class=\"token keyword\">implements</span> <span class=\"token class-name\">InspectionToolProvider</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token keyword\">public</span> <span class=\"token class-name\">Class</span><span class=\"token punctuation\">[</span><span class=\"token punctuation\">]</span> <span class=\"token function\">getInspectionClasses</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 keyword\">new</span> <span class=\"token class-name\">Class</span><span class=\"token punctuation\">[</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">{</span>\n                <span class=\"token class-name\">DirtiesContextInspection</span><span class=\"token punctuation\">.</span><span class=\"token keyword\">class</span>\n        <span class=\"token punctuation\">}</span><span class=\"token punctuation\">;</span>\n    <span class=\"token punctuation\">}</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<p>And register it in <code class=\"language-text\">plugin.xml</code>:</p>\n<div class=\"gatsby-highlight\" data-language=\"xml\"><pre class=\"language-xml\"><code class=\"language-xml\">   <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>extensions</span> <span class=\"token attr-name\">defaultExtensionNs</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>com.intellij<span class=\"token punctuation\">\"</span></span><span class=\"token punctuation\">></span></span>\n        <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>inspectionToolProvider</span> <span class=\"token attr-name\">implementation</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>com.auto1.intellij.tutorial.CodeInspectionProvider<span class=\"token punctuation\">\"</span></span><span class=\"token punctuation\">/></span></span>\n    <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>extensions</span><span class=\"token punctuation\">></span></span></code></pre></div>\n<p>Now it’s time to check our inspection in action by running runIde gradle task. This could be done from terminal by executing <code class=\"language-text\">./gradlew runIde</code> but it’s better to use Gradle view in IntelliJ since it allows to start IDE in debug mode (if needed just right click on task and select Debug, you can create run configuration to speed-up in the future). New IntelliJ instance should show up, if you already have sources of some project that uses Spring Boot then open it, otherwise you could create a new project. Annotate some class with <code class=\"language-text\">@DirtiesContext</code> annotation and observe inspection marker showing up. In case of problems logs can be found at <code class=\"language-text\">build/idea-sandbox/system/log/</code>.</p>\n<h2>Adding quick fix</h2>\n<p>Many inspections report not only problems but also provide automatic ways of fixing issues. In case of DirtiesContext, it’s not possible to provide safe way of removing it because DirtiesContext is often used when bean holds some state which makes tests dependent on each other. Usually we want to remove the annotation and then figure out the \"dirty parts\" and clean them up in an elegant way. Since the second part is hard to automate we will provide quick fix which only removes annotation.</p>\n<p>Go back to <code class=\"language-text\">DirtiesContextInspection</code> class and add quick fix:</p>\n<div class=\"gatsby-highlight\" data-language=\"java\"><pre class=\"language-java\"><code class=\"language-java\">   <span class=\"token keyword\">private</span> <span class=\"token keyword\">static</span> <span class=\"token keyword\">class</span> <span class=\"token class-name\">DeleteQuickFix</span> <span class=\"token keyword\">implements</span> <span class=\"token class-name\">LocalQuickFix</span> <span class=\"token punctuation\">{</span>\n        <span class=\"token keyword\">public</span> <span class=\"token class-name\">String</span> <span class=\"token function\">getName</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 string\">\"Removes usage of @DirtiesContext\"</span><span class=\"token punctuation\">;</span>\n        <span class=\"token punctuation\">}</span>\n\n        <span class=\"token keyword\">public</span> <span class=\"token keyword\">void</span> <span class=\"token function\">applyFix</span><span class=\"token punctuation\">(</span><span class=\"token annotation punctuation\">@NotNull</span> <span class=\"token class-name\">Project</span> project<span class=\"token punctuation\">,</span> <span class=\"token annotation punctuation\">@NotNull</span> <span class=\"token class-name\">ProblemDescriptor</span> descriptor<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n            descriptor<span class=\"token punctuation\">.</span><span class=\"token function\">getPsiElement</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span><span class=\"token function\">delete</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 keyword\">public</span> <span class=\"token class-name\">String</span> <span class=\"token function\">getFamilyName</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 function\">getName</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n        <span class=\"token punctuation\">}</span>\n    <span class=\"token punctuation\">}</span></code></pre></div>\n<p>Next step is to pass quick fix when problem is registered:</p>\n<div class=\"gatsby-highlight\" data-language=\"java\"><pre class=\"language-java\"><code class=\"language-java\">holder<span class=\"token punctuation\">.</span><span class=\"token function\">registerProblem</span><span class=\"token punctuation\">(</span>annotation<span class=\"token punctuation\">,</span> DESCRIPTION_TEMPLATE<span class=\"token punctuation\">,</span> <span class=\"token keyword\">new</span> <span class=\"token class-name\">DeleteQuickFix</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></code></pre></div>\n<p>Executing <code class=\"language-text\">runIde</code> Gradle task should prove that quick fix works as expected. </p>\n<h2>Internationalization</h2>\n<p>Up to this point we have used hardcoded strings inside inspection name and description. To allow the plugin to be accessible in different languages we can externalize the messages. For this purpose we can use properties file. First create <code class=\"language-text\">PluginBundle</code> class:</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\">PluginBundle</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token keyword\">private</span> <span class=\"token keyword\">static</span> <span class=\"token class-name\">Reference</span><span class=\"token generics\"><span class=\"token punctuation\">&lt;</span><span class=\"token class-name\">ResourceBundle</span><span class=\"token punctuation\">></span></span> ourBundle<span class=\"token punctuation\">;</span>\n\n    <span class=\"token keyword\">private</span> <span class=\"token keyword\">static</span> <span class=\"token keyword\">final</span> <span class=\"token class-name\">String</span> BUNDLE <span class=\"token operator\">=</span> <span class=\"token string\">\"com.auto1.intellij.tutorial.PluginBundle\"</span><span class=\"token punctuation\">;</span>\n\n    <span class=\"token keyword\">private</span> <span class=\"token class-name\">PluginBundle</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span> <span class=\"token punctuation\">}</span>\n\n    <span class=\"token keyword\">public</span> <span class=\"token keyword\">static</span> <span class=\"token class-name\">String</span> <span class=\"token function\">message</span><span class=\"token punctuation\">(</span><span class=\"token annotation punctuation\">@NotNull</span> <span class=\"token annotation punctuation\">@PropertyKey</span><span class=\"token punctuation\">(</span>resourceBundle <span class=\"token operator\">=</span> BUNDLE<span class=\"token punctuation\">)</span> <span class=\"token class-name\">String</span> key<span class=\"token punctuation\">,</span> \n                                 <span class=\"token annotation punctuation\">@NotNull</span> <span class=\"token class-name\">Object</span><span class=\"token punctuation\">.</span><span class=\"token punctuation\">.</span><span class=\"token punctuation\">.</span> params<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n        <span class=\"token keyword\">return</span> <span class=\"token class-name\">CommonBundle</span><span class=\"token punctuation\">.</span><span class=\"token function\">message</span><span class=\"token punctuation\">(</span><span class=\"token function\">getBundle</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span> key<span class=\"token punctuation\">,</span> params<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    <span class=\"token punctuation\">}</span>\n\n    <span class=\"token keyword\">private</span> <span class=\"token keyword\">static</span> <span class=\"token class-name\">ResourceBundle</span> <span class=\"token function\">getBundle</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n        <span class=\"token class-name\">ResourceBundle</span> bundle <span class=\"token operator\">=</span> <span class=\"token class-name\"><span class=\"token namespace\">com<span class=\"token punctuation\">.</span>intellij<span class=\"token punctuation\">.</span>reference<span class=\"token punctuation\">.</span></span>SoftReference</span><span class=\"token punctuation\">.</span><span class=\"token function\">dereference</span><span class=\"token punctuation\">(</span>ourBundle<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n        <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span>bundle <span class=\"token operator\">==</span> <span class=\"token keyword\">null</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n            bundle <span class=\"token operator\">=</span> <span class=\"token class-name\">ResourceBundle</span><span class=\"token punctuation\">.</span><span class=\"token function\">getBundle</span><span class=\"token punctuation\">(</span>BUNDLE<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n            ourBundle <span class=\"token operator\">=</span> <span class=\"token keyword\">new</span> <span class=\"token class-name\">SoftReference</span><span class=\"token generics\"><span class=\"token punctuation\">&lt;</span><span class=\"token punctuation\">></span></span><span class=\"token punctuation\">(</span>bundle<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n        <span class=\"token punctuation\">}</span>\n        <span class=\"token keyword\">return</span> bundle<span class=\"token punctuation\">;</span>\n    <span class=\"token punctuation\">}</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<p>Then create a new file matching <code class=\"language-text\">BUNDLE</code> constant, in my case it will be <code class=\"language-text\">src/main/resources/com/auto1/intellij/tutorial/PluginBundle.properties</code> with content:</p>\n<div class=\"gatsby-highlight\" data-language=\"properties\"><pre class=\"language-properties\"><code class=\"language-properties\"><span class=\"token attr-name\">inspection.dirties.context.display.name</span><span class=\"token punctuation\">=</span><span class=\"token attr-value\">Usage of @DirtiesContext is not recommended</span>\n<span class=\"token attr-name\">inspection.dirties.context.problem.descriptor</span><span class=\"token punctuation\">=</span><span class=\"token attr-value\">Usage of @DirtiesContext makes integration tests slower</span>\n<span class=\"token attr-name\">inspection.dirties.context.use.quickfix</span><span class=\"token punctuation\">=</span><span class=\"token attr-value\">Removes usage of @DirtiesContext</span></code></pre></div>\n<p>Register bundle in <code class=\"language-text\">plugin.xml</code>:</p>\n<div class=\"gatsby-highlight\" data-language=\"xml\"><pre class=\"language-xml\"><code class=\"language-xml\"><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>resource-bundle</span><span class=\"token punctuation\">></span></span>com.auto1.intellij.tutorial.PluginBundle<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>resource-bundle</span><span class=\"token punctuation\">></span></span></code></pre></div>\n<p>And finally use bundle in inspection, for example:</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 class-name\">String</span> <span class=\"token function\">getDisplayName</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 class-name\">PluginBundle</span><span class=\"token punctuation\">.</span><span class=\"token function\">message</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"inspection.dirties.context.display.name\"</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    <span class=\"token punctuation\">}</span></code></pre></div>\n<h2>Testing</h2>\n<p>We picked <code class=\"language-text\">LightPlatformCodeInsightFixtureTestCase</code> as base for our tests because it is recommended in the documentation. Unfortunately, testing appeared harder to set up properly than expected.</p>\n<p>First problem was that our tests couldn’t see classes from JDK, which was fixed by specifying project descriptor to use internal JDK: </p>\n<div class=\"gatsby-highlight\" data-language=\"java\"><pre class=\"language-java\"><code class=\"language-java\">    <span class=\"token keyword\">protected</span> <span class=\"token class-name\">LightProjectDescriptor</span> <span class=\"token function\">getProjectDescriptor</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 keyword\">new</span> <span class=\"token class-name\">LightProjectDescriptor</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n            <span class=\"token keyword\">public</span> <span class=\"token class-name\">Sdk</span> <span class=\"token function\">getSdk</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 class-name\">JavaAwareProjectJdkTableImpl</span><span class=\"token punctuation\">.</span><span class=\"token function\">getInstanceEx</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span><span class=\"token function\">getInternalJdk</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n            <span class=\"token punctuation\">}</span>\n        <span class=\"token punctuation\">}</span><span class=\"token punctuation\">;</span>\n    <span class=\"token punctuation\">}</span></code></pre></div>\n<p>Second problem was that visitor received incorrect fully qualified class name of the annotation. Instead of <code class=\"language-text\">org.springframework.test.annotation.DirtiesContext</code>, it got <code class=\"language-text\">DirtiesContext</code> while it worked fine for real project in IDE. It turns out that such behaviour occurs when test project doesn’t see definition of some class. This is fixable by either hardcoding problematic class into test or by adding dependency as library to the project. Second approach avoids copying source code from other projects and seems to be more interesting so it will be presented here. In order to download dependency jar we use <code class=\"language-text\">ShrinkWrap</code> library:</p>\n<div class=\"gatsby-highlight\" data-language=\"java\"><pre class=\"language-java\"><code class=\"language-java\"><span class=\"token keyword\">private</span> <span class=\"token class-name\">File</span><span class=\"token punctuation\">[</span><span class=\"token punctuation\">]</span> <span class=\"token function\">getMavenArtifacts</span><span class=\"token punctuation\">(</span><span class=\"token class-name\">String</span><span class=\"token punctuation\">.</span><span class=\"token punctuation\">.</span><span class=\"token punctuation\">.</span> mavenArtifacts<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n        <span class=\"token class-name\">File</span><span class=\"token punctuation\">[</span><span class=\"token punctuation\">]</span> files <span class=\"token operator\">=</span> <span class=\"token class-name\">Maven</span><span class=\"token punctuation\">.</span><span class=\"token function\">resolver</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span>\n                            <span class=\"token punctuation\">.</span><span class=\"token function\">resolve</span><span class=\"token punctuation\">(</span>mavenArtifacts<span class=\"token punctuation\">)</span>\n                            <span class=\"token punctuation\">.</span><span class=\"token function\">withoutTransitivity</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span>\n                            <span class=\"token punctuation\">.</span><span class=\"token function\">asFile</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n        <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span>files<span class=\"token punctuation\">.</span>length <span class=\"token operator\">==</span> <span class=\"token number\">0</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n            <span class=\"token keyword\">throw</span> <span class=\"token keyword\">new</span> <span class=\"token class-name\">IllegalArgumentException</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"Failed to resolve artifacts \"</span> <span class=\"token operator\">+</span> <span class=\"token class-name\">Arrays</span><span class=\"token punctuation\">.</span><span class=\"token function\">toString</span><span class=\"token punctuation\">(</span>mavenArtifacts<span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n        <span class=\"token punctuation\">}</span>\n        <span class=\"token keyword\">return</span> files<span class=\"token punctuation\">;</span>\n    <span class=\"token punctuation\">}</span></code></pre></div>\n<p>When dependency is resolved and downloaded into local Maven cache it can be added as library with code listed below:</p>\n<div class=\"gatsby-highlight\" data-language=\"java\"><pre class=\"language-java\"><code class=\"language-java\">   <span class=\"token keyword\">protected</span> <span class=\"token keyword\">void</span> <span class=\"token function\">attachMavenLibrary</span><span class=\"token punctuation\">(</span><span class=\"token class-name\">String</span> mavenArtifact<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n        <span class=\"token class-name\">File</span><span class=\"token punctuation\">[</span><span class=\"token punctuation\">]</span> jars <span class=\"token operator\">=</span> <span class=\"token function\">getMavenArtifacts</span><span class=\"token punctuation\">(</span>mavenArtifact<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n        <span class=\"token class-name\">Arrays</span><span class=\"token punctuation\">.</span><span class=\"token function\">stream</span><span class=\"token punctuation\">(</span>jars<span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span><span class=\"token function\">forEach</span><span class=\"token punctuation\">(</span>jar <span class=\"token operator\">-></span> <span class=\"token punctuation\">{</span>\n            <span class=\"token class-name\">String</span> name <span class=\"token operator\">=</span> jar<span class=\"token punctuation\">.</span><span class=\"token function\">getName</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n            <span class=\"token class-name\">PsiTestUtil</span><span class=\"token punctuation\">.</span><span class=\"token function\">addLibrary</span><span class=\"token punctuation\">(</span>myFixture<span class=\"token punctuation\">.</span><span class=\"token function\">getProjectDisposable</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span> myModule<span class=\"token punctuation\">,</span> name<span class=\"token punctuation\">,</span> jar<span class=\"token punctuation\">.</span><span class=\"token function\">getParent</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span> name<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>\n    <span class=\"token punctuation\">}</span></code></pre></div>\n<p>It’s important to use <code class=\"language-text\">myFixture.getProjectDisposable()</code> instead of <code class=\"language-text\">myFixture.getProject()</code> otherwise there is an exception during test shutdown:</p>\n<div class=\"gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">com.intellij.openapi.util.TraceableDisposable$DisposalException: Virtual pointer 'jar:///somePath/.m2/repository/org/springframework/spring-test/5.1.5.RELEASE/spring-test-5.1.5.RELEASE.jar!/' hasn't been disposed</code></pre></div>\n<p>Next surprise is that by default test searches for test data in strange location inside IntelliJ home folder which can be fixed with overriding <code class=\"language-text\">getTestDataPath</code>. Since input files most likely won’t compile because of missing imports and possible usage of special markers like <em><caret></em> we don’t use <code class=\"language-text\">src/test/java</code> folder to store them:</p>\n<div class=\"gatsby-highlight\" data-language=\"java\"><pre class=\"language-java\"><code class=\"language-java\">    <span class=\"token annotation punctuation\">@Override</span>\n    <span class=\"token keyword\">protected</span> <span class=\"token class-name\">String</span> <span class=\"token function\">getTestDataPath</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 string\">\"src/test/testData\"</span><span class=\"token punctuation\">;</span>\n    <span class=\"token punctuation\">}</span></code></pre></div>\n<p>Inspection tests can be done by providing file to analyse and resulting file that should be created after given quick fix has been applied. Inspection tests use <code class=\"language-text\">configureByFile</code> to load input file, <code class=\"language-text\">doHighlighting</code> to trigger source code analysis, launchAction to execute quick fix and finally <code class=\"language-text\">checkResultByFile</code> to compare results against <em>after</em> file.</p>\n<div class=\"gatsby-highlight\" data-language=\"java\"><pre class=\"language-java\"><code class=\"language-java\">    myFixture<span class=\"token punctuation\">.</span><span class=\"token function\">configureByFile</span><span class=\"token punctuation\">(</span>testName <span class=\"token operator\">+</span> <span class=\"token string\">\".java\"</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    myFixture<span class=\"token punctuation\">.</span><span class=\"token function\">enableInspections</span><span class=\"token punctuation\">(</span><span class=\"token keyword\">new</span> <span class=\"token class-name\">DirtiesContextInspection</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    myFixture<span class=\"token punctuation\">.</span><span class=\"token function\">doHighlighting</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    <span class=\"token class-name\">IntentionAction</span> quickFixAction <span class=\"token operator\">=</span> myFixture<span class=\"token punctuation\">.</span><span class=\"token function\">findSingleIntention</span><span class=\"token punctuation\">(</span>intentionHint<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    myFixture<span class=\"token punctuation\">.</span><span class=\"token function\">launchAction</span><span class=\"token punctuation\">(</span>quickFixAction<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    myFixture<span class=\"token punctuation\">.</span><span class=\"token function\">checkResultByFile</span><span class=\"token punctuation\">(</span>testName <span class=\"token operator\">+</span> <span class=\"token string\">\".after.java\"</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></code></pre></div>\n<p>Complete source code can be found at github <a href=\"https://github.com/pczekaj/tutorial-intellij-plugin\">github</a></p>\n<h2>Next steps</h2>\n<p>If you would like to share your plugin with other developers, you can publish to JetBrains plugin repository as described in the documentation. Other simple option is to execute buildPlugin Gradle task which will create plugin zip file inside build/distributions and then install it via <em>Install Plugin from disk...</em> available inside <em>Preferences > Plugins</em> (in IntelliJ 2018.3 is available through \"gears icon\").</p>\n<p>When working on your own ideas you might run into a situation when you don't know how to implement some functionality. In this situation you could try to find the answer using links provided in section below. What also worked for us was reading source code of inspections available as part of community edition of IntelliJ, often there is an existing inspection which does a similar thing to what you might want to do.</p>\n<h2>Links</h2>\n<ul>\n<li><a href=\"http://www.jetbrains.org/intellij/sdk/docs/faq.html\">IntelliJ SDK FAQ</a></li>\n<li><a href=\"https://github.com/JetBrains/intellij-sdk-docs/blob/master/tutorials/code_inspections.md\">Code inspections tutorial</a></li>\n<li><a href=\"https://intellij-support.jetbrains.com/hc/en-us/community/topics/200366979-IntelliJ-IDEA-Open-API-and-Plugin-Development\">Plugin development forum</a></li>\n<li><a href=\"https://github.com/JetBrains/intellij-community\">Source code of IntelliJ community edition</a></li>\n<li><a href=\"https://github.com/JetBrains/intellij-plugins\">Source code of many IntelliJ plugins</a></li>\n</ul>","fields":{"slug":"/intellij-plugin/","tags":["intellij"]}}},{"node":{"id":"24fd2709-272a-5811-a69c-7100924de21c","frontmatter":{"category":"Coding","title":"Serving JSON (almost) directly from database","date":"2019-10-29","summary":"Learn how to query JSON data from Postgres 12 to improve Java application's performance.","thumbnail":{"relativePath":"pages/serving-json-from-postgres/liberty.jpg","childImageSharp":{"resolutions":{"base64":"data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAUABQDASIAAhEBAxEB/8QAGAABAAMBAAAAAAAAAAAAAAAAAAIDBAX/xAAUAQEAAAAAAAAAAAAAAAAAAAAA/9oADAMBAAIQAxAAAAHryz0HUYxXEAP/xAAbEAABBAMAAAAAAAAAAAAAAAABAgMSIhAgIf/aAAgBAQABBQJw0SoKxLjVDPT/xAAUEQEAAAAAAAAAAAAAAAAAAAAg/9oACAEDAQE/AR//xAAUEQEAAAAAAAAAAAAAAAAAAAAg/9oACAECAQE/AR//xAAYEAACAwAAAAAAAAAAAAAAAAABIQAQIP/aAAgBAQAGPwJRGzn/xAAaEAEAAwADAAAAAAAAAAAAAAABABEhEDGB/9oACAEBAAE/IVEqq3yWWlcbozCOmOokIz//2gAMAwEAAgADAAAAEOAPAP/EABQRAQAAAAAAAAAAAAAAAAAAACD/2gAIAQMBAT8QH//EABQRAQAAAAAAAAAAAAAAAAAAACD/2gAIAQIBAT8QH//EABwQAQADAQADAQAAAAAAAAAAAAEAETEhQXGhwf/aAAgBAQABPxBIyYq1CL8uc5XU14YIGwTYJTDeFrX2G/k7OwjIAbIBek//2Q==","width":325,"height":325,"src":"/static/e0de7302edcea3d0b0c19a9d147b547a/a2998/liberty.jpg","srcSet":"/static/e0de7302edcea3d0b0c19a9d147b547a/a2998/liberty.jpg 1x,\n/static/e0de7302edcea3d0b0c19a9d147b547a/99cce/liberty.jpg 1.5x,\n/static/e0de7302edcea3d0b0c19a9d147b547a/6e995/liberty.jpg 2x,\n/static/e0de7302edcea3d0b0c19a9d147b547a/968b1/liberty.jpg 3x"}}},"authorName":"Mariusz Nowak","authorDescription":"Mariusz is a Senior Software Engineer at AUTO1 Group.","authorAvatar":null,"headerImage":null},"html":"<p>RESTful API’s are ruling the industry nowadays. They are very often associated with an extremely popular data format - JSON.\nIt is so popular that database creators decided to implement it directly in the database engines.\nAll modern databases offer JSON processing capabilities.\nLet’s have a look and see how can we make use of them to improve our application’s performance.</p>\n<h3>JPA or JDBC?</h3>\n<p>The typical choice for a Java application is to use JPA as the persistence layer abstraction.\nIt became the de-facto standard for a reason - it offers great flexibility and ease of use.\nUnfortunately it doesn't come without a price since we have to pay with degraded performance.</p>\n<p>It is a widely known fact that <strong>ORM’s impact performance</strong>, compared to pure JDBC.\nOn the other hand, relatively few are willing to use plain JDBC, considering the amount of additional work it requires.</p>\n<p>Let me demonstrate how to use JDBC to leverage the performance, with the help of modern Postgres features.</p>\n<h3>Demo time</h3>\n<p>I have prepared a <a href=\"https://github.com/auto1-oss/postgres12-json-demo\">demo application</a> running on Spring Boot which exposes example data from the <a href=\"https://github.com/pthom/northwind_psql\">northwind</a> database.\nThe data are exposed in three different ways.</p>\n<p>The baseline version simply exposes JPA entities:</p>\n<div class=\"gatsby-highlight\" data-language=\"java\"><pre class=\"language-java\"><code class=\"language-java\"><span class=\"token annotation punctuation\">@GetMapping</span><span class=\"token punctuation\">(</span>path <span class=\"token operator\">=</span> <span class=\"token string\">\"/v1/orders/{order_id}\"</span><span class=\"token punctuation\">,</span>\n            produces <span class=\"token operator\">=</span> APPLICATION_JSON_VALUE<span class=\"token punctuation\">)</span>\n<span class=\"token keyword\">public</span> <span class=\"token class-name\">Order</span> <span class=\"token function\">getEntity</span><span class=\"token punctuation\">(</span><span class=\"token annotation punctuation\">@PathVariable</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"order_id\"</span><span class=\"token punctuation\">)</span> <span class=\"token class-name\">Integer</span> orderId<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token keyword\">return</span> orderRepository<span class=\"token punctuation\">.</span><span class=\"token function\">findById</span><span class=\"token punctuation\">(</span>orderId<span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span><span class=\"token function\">orElseThrow</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>The Order entity aggregates data from numerous database tables: <code class=\"language-text\">orders</code>, <code class=\"language-text\">order_details</code>, <code class=\"language-text\">products</code>, <code class=\"language-text\">customers</code>, <code class=\"language-text\">customer_customer_demo</code> and <code class=\"language-text\">customer_demographics</code>.\nYou could check the corresponding JPA mapping <a href=\"https://github.com/auto1-oss/postgres12-json-demo/tree/postgres-12/src/main/java/com/auto1/postgres12/jpa\">here</a>.</p>\n<p>Thanks to the magic of Spring the entity is being translated into a JSON response:</p>\n<div class=\"gatsby-highlight\" data-language=\"json\"><pre class=\"language-json\"><code class=\"language-json\"><span class=\"token punctuation\">{</span>\n  <span class=\"token property\">\"orderId\"</span><span class=\"token operator\">:</span> <span class=\"token number\">10284</span><span class=\"token punctuation\">,</span>\n  <span class=\"token property\">\"employeeId\"</span><span class=\"token operator\">:</span> <span class=\"token number\">4</span><span class=\"token punctuation\">,</span>\n  <span class=\"token property\">\"orderDate\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"1996-08-19\"</span><span class=\"token punctuation\">,</span>\n  <span class=\"token property\">\"requiredDate\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"1996-09-16\"</span><span class=\"token punctuation\">,</span>\n  <span class=\"token property\">\"shippedDate\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"1996-08-27\"</span><span class=\"token punctuation\">,</span>\n  <span class=\"token property\">\"shipVia\"</span><span class=\"token operator\">:</span> <span class=\"token number\">1</span><span class=\"token punctuation\">,</span>\n  <span class=\"token property\">\"freight\"</span><span class=\"token operator\">:</span> <span class=\"token number\">76.56</span><span class=\"token punctuation\">,</span>\n  <span class=\"token property\">\"shipName\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"Lehmanns Marktstand\"</span><span class=\"token punctuation\">,</span>\n  <span class=\"token property\">\"shipAddress\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"Magazinweg 7\"</span><span class=\"token punctuation\">,</span>\n  <span class=\"token property\">\"shipCity\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"Frankfurt a.M.\"</span><span class=\"token punctuation\">,</span>\n  <span class=\"token property\">\"shipRegion\"</span><span class=\"token operator\">:</span> <span class=\"token null keyword\">null</span><span class=\"token punctuation\">,</span>\n  <span class=\"token property\">\"shipPostalCode\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"60528\"</span><span class=\"token punctuation\">,</span>\n  <span class=\"token property\">\"shipCountry\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"Germany\"</span><span class=\"token punctuation\">,</span>\n  <span class=\"token property\">\"orderDetails\"</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">[</span>\n    <span class=\"token punctuation\">{</span>\n      <span class=\"token property\">\"orderId\"</span><span class=\"token operator\">:</span> <span class=\"token number\">10284</span><span class=\"token punctuation\">,</span>\n      <span class=\"token property\">\"productId\"</span><span class=\"token operator\">:</span> <span class=\"token number\">27</span><span class=\"token punctuation\">,</span>\n      <span class=\"token property\">\"product\"</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">{</span>\n        <span class=\"token property\">\"productId\"</span><span class=\"token operator\">:</span> <span class=\"token number\">27</span><span class=\"token punctuation\">,</span>\n        <span class=\"token property\">\"categoryId\"</span><span class=\"token operator\">:</span> <span class=\"token number\">3</span><span class=\"token punctuation\">,</span>\n        <span class=\"token property\">\"supplierId\"</span><span class=\"token operator\">:</span> <span class=\"token number\">11</span><span class=\"token punctuation\">,</span>\n        <span class=\"token property\">\"productName\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"Schoggi Schokolade\"</span><span class=\"token punctuation\">,</span>\n        <span class=\"token property\">\"discontinued\"</span><span class=\"token operator\">:</span> <span class=\"token boolean\">false</span><span class=\"token punctuation\">,</span>\n        <span class=\"token property\">\"quantityPerUnit\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"100 - 100 g pieces\"</span><span class=\"token punctuation\">,</span>\n        <span class=\"token property\">\"unitPrice\"</span><span class=\"token operator\">:</span> <span class=\"token number\">43.9</span><span class=\"token punctuation\">,</span>\n        <span class=\"token property\">\"unitsInStock\"</span><span class=\"token operator\">:</span> <span class=\"token number\">49</span><span class=\"token punctuation\">,</span>\n        <span class=\"token property\">\"unitsOnOrder\"</span><span class=\"token operator\">:</span> <span class=\"token number\">0</span><span class=\"token punctuation\">,</span>\n        <span class=\"token property\">\"reorderLevel\"</span><span class=\"token operator\">:</span> <span class=\"token number\">30</span>\n      <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span>\n      <span class=\"token property\">\"unitPrice\"</span><span class=\"token operator\">:</span> <span class=\"token number\">35.1</span><span class=\"token punctuation\">,</span>\n      <span class=\"token property\">\"quantity\"</span><span class=\"token operator\">:</span> <span class=\"token number\">15</span><span class=\"token punctuation\">,</span>\n      <span class=\"token property\">\"discount\"</span><span class=\"token operator\">:</span> <span class=\"token number\">0.25</span>\n    <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>\n    <span class=\"token punctuation\">{</span>...<span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span>\n    <span class=\"token punctuation\">{</span>...<span class=\"token punctuation\">}</span>\n  <span class=\"token punctuation\">]</span><span class=\"token punctuation\">,</span>\n  <span class=\"token property\">\"customer\"</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token property\">\"customerId\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"LEHMS\"</span><span class=\"token punctuation\">,</span>\n    <span class=\"token property\">\"companyName\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"Lehmanns Marktstand\"</span><span class=\"token punctuation\">,</span>\n    <span class=\"token property\">\"contactName\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"Renate Messner\"</span><span class=\"token punctuation\">,</span>\n    <span class=\"token property\">\"contactTitle\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"Sales Representative\"</span><span class=\"token punctuation\">,</span>\n    <span class=\"token property\">\"address\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"Magazinweg 7\"</span><span class=\"token punctuation\">,</span>\n    <span class=\"token property\">\"city\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"Frankfurt a.M.\"</span><span class=\"token punctuation\">,</span>\n    <span class=\"token property\">\"region\"</span><span class=\"token operator\">:</span> <span class=\"token null keyword\">null</span><span class=\"token punctuation\">,</span>\n    <span class=\"token property\">\"postalCode\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"60528\"</span><span class=\"token punctuation\">,</span>\n    <span class=\"token property\">\"country\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"Germany\"</span><span class=\"token punctuation\">,</span>\n    <span class=\"token property\">\"phone\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"069-0245984\"</span><span class=\"token punctuation\">,</span>\n    <span class=\"token property\">\"fax\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"069-0245874\"</span><span class=\"token punctuation\">,</span>\n    <span class=\"token property\">\"customerDesc\"</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">[</span>\n      <span class=\"token punctuation\">{</span>\n        <span class=\"token property\">\"customerTypeId\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"AAAA\"</span><span class=\"token punctuation\">,</span>\n        <span class=\"token property\">\"customerDesc\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"First demographic\"</span>\n      <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>\n      <span class=\"token punctuation\">{</span>...<span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span>\n      <span class=\"token punctuation\">{</span>...<span class=\"token punctuation\">}</span>\n    <span class=\"token punctuation\">]</span>\n  <span class=\"token punctuation\">}</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<p>The demo project includes the p6spy library which gives an insight into the queries being issued against database.\nTurns out that <strong>three queries</strong> are required to load a particular Order - this means <strong>three database round trips</strong>.</p>\n<p>Of course we can force the ORM to join all the tables and fetch them in one hop, but this seems a not so elegant solution -\nit pushes the ORM to load duplicated data and the necessity of deduplicating them in-memory. Can we do better?</p>\n<h3>JDBC to the rescue</h3>\n<p>JDBC is always a choice if the solution could be expressed via SQL query. Luckily we can create one which matches our case perfectly:</p>\n<div class=\"gatsby-highlight\" data-language=\"sql\"><pre class=\"language-sql\"><code class=\"language-sql\"><span class=\"token keyword\">WITH</span> products<span class=\"token punctuation\">(</span><span class=\"token string\">\"productId\"</span><span class=\"token punctuation\">,</span> <span class=\"token string\">\"categoryId\"</span><span class=\"token punctuation\">,</span> <span class=\"token string\">\"supplierId\"</span><span class=\"token punctuation\">,</span> <span class=\"token string\">\"productName\"</span><span class=\"token punctuation\">,</span> <span class=\"token string\">\"discontinued\"</span><span class=\"token punctuation\">,</span> <span class=\"token string\">\"quantityPerUnit\"</span><span class=\"token punctuation\">,</span>\n              <span class=\"token string\">\"unitPrice\"</span><span class=\"token punctuation\">,</span> <span class=\"token string\">\"unitsInStock\"</span><span class=\"token punctuation\">,</span> <span class=\"token string\">\"unitsOnOrder\"</span><span class=\"token punctuation\">,</span> <span class=\"token string\">\"reorderLevel\"</span><span class=\"token punctuation\">)</span> <span class=\"token keyword\">AS</span>\n         <span class=\"token punctuation\">(</span><span class=\"token keyword\">SELECT</span> p<span class=\"token punctuation\">.</span>product_id<span class=\"token punctuation\">,</span>\n                 p<span class=\"token punctuation\">.</span>category_id<span class=\"token punctuation\">,</span>\n                 p<span class=\"token punctuation\">.</span>supplier_id<span class=\"token punctuation\">,</span>\n                 p<span class=\"token punctuation\">.</span>product_name<span class=\"token punctuation\">,</span>\n                 p<span class=\"token punctuation\">.</span>discontinued::<span class=\"token keyword\">boolean</span><span class=\"token punctuation\">,</span>\n                 p<span class=\"token punctuation\">.</span>quantity_per_unit<span class=\"token punctuation\">,</span>\n                 p<span class=\"token punctuation\">.</span>unit_price<span class=\"token punctuation\">,</span>\n                 p<span class=\"token punctuation\">.</span>units_in_stock<span class=\"token punctuation\">,</span>\n                 p<span class=\"token punctuation\">.</span>units_on_order<span class=\"token punctuation\">,</span>\n                 p<span class=\"token punctuation\">.</span>reorder_level\n          <span class=\"token keyword\">FROM</span> products p<span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span>\n     orderDetails<span class=\"token punctuation\">(</span><span class=\"token string\">\"orderId\"</span><span class=\"token punctuation\">,</span> <span class=\"token string\">\"productId\"</span><span class=\"token punctuation\">,</span> <span class=\"token string\">\"product\"</span><span class=\"token punctuation\">,</span> <span class=\"token string\">\"unitPrice\"</span><span class=\"token punctuation\">,</span> <span class=\"token string\">\"quantity\"</span><span class=\"token punctuation\">,</span> <span class=\"token string\">\"discount\"</span><span class=\"token punctuation\">)</span> <span class=\"token keyword\">AS</span>\n         <span class=\"token punctuation\">(</span><span class=\"token keyword\">SELECT</span> d<span class=\"token punctuation\">.</span>order_id<span class=\"token punctuation\">,</span>\n                 d<span class=\"token punctuation\">.</span>product_id<span class=\"token punctuation\">,</span>\n                 <span class=\"token punctuation\">(</span><span class=\"token keyword\">SELECT</span> to_json<span class=\"token punctuation\">(</span>p<span class=\"token punctuation\">)</span> <span class=\"token keyword\">FROM</span> products p <span class=\"token keyword\">WHERE</span> p<span class=\"token punctuation\">.</span><span class=\"token string\">\"productId\"</span> <span class=\"token operator\">=</span> d<span class=\"token punctuation\">.</span>product_id<span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span>\n                 d<span class=\"token punctuation\">.</span>unit_price<span class=\"token punctuation\">,</span>\n                 d<span class=\"token punctuation\">.</span>quantity<span class=\"token punctuation\">,</span>\n                 d<span class=\"token punctuation\">.</span>discount\n          <span class=\"token keyword\">FROM</span> order_details d<span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span>\n\n     demographics<span class=\"token punctuation\">(</span><span class=\"token string\">\"customerId\"</span><span class=\"token punctuation\">,</span> <span class=\"token string\">\"customerTypeId\"</span><span class=\"token punctuation\">,</span> <span class=\"token string\">\"customerDesc\"</span><span class=\"token punctuation\">)</span> <span class=\"token keyword\">AS</span>\n         <span class=\"token punctuation\">(</span><span class=\"token keyword\">SELECT</span> ccd<span class=\"token punctuation\">.</span>customer_id<span class=\"token punctuation\">,</span>\n                 ccd<span class=\"token punctuation\">.</span>customer_type_id<span class=\"token punctuation\">,</span>\n                 cd<span class=\"token punctuation\">.</span>customer_desc\n          <span class=\"token keyword\">FROM</span> customer_demographics cd\n                   <span class=\"token keyword\">JOIN</span> customer_customer_demo ccd <span class=\"token keyword\">on</span> cd<span class=\"token punctuation\">.</span>customer_type_id <span class=\"token operator\">=</span> ccd<span class=\"token punctuation\">.</span>customer_type_id<span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span>\n     customers<span class=\"token punctuation\">(</span><span class=\"token string\">\"customerId\"</span><span class=\"token punctuation\">,</span> <span class=\"token string\">\"companyName\"</span><span class=\"token punctuation\">,</span> <span class=\"token string\">\"contactName\"</span><span class=\"token punctuation\">,</span> <span class=\"token string\">\"contactTitle\"</span><span class=\"token punctuation\">,</span> <span class=\"token string\">\"address\"</span><span class=\"token punctuation\">,</span> <span class=\"token string\">\"city\"</span><span class=\"token punctuation\">,</span> <span class=\"token string\">\"region\"</span><span class=\"token punctuation\">,</span> <span class=\"token string\">\"postalCode\"</span><span class=\"token punctuation\">,</span>\n               <span class=\"token string\">\"country\"</span><span class=\"token punctuation\">,</span> <span class=\"token string\">\"phone\"</span><span class=\"token punctuation\">,</span> <span class=\"token string\">\"fax\"</span><span class=\"token punctuation\">,</span> <span class=\"token string\">\"customerDesc\"</span><span class=\"token punctuation\">)</span> <span class=\"token keyword\">AS</span>\n         <span class=\"token punctuation\">(</span><span class=\"token keyword\">SELECT</span> c<span class=\"token punctuation\">.</span>customer_id<span class=\"token punctuation\">,</span>\n                 c<span class=\"token punctuation\">.</span>company_name<span class=\"token punctuation\">,</span>\n                 c<span class=\"token punctuation\">.</span>contact_name<span class=\"token punctuation\">,</span>\n                 c<span class=\"token punctuation\">.</span>contact_title<span class=\"token punctuation\">,</span>\n                 c<span class=\"token punctuation\">.</span>address<span class=\"token punctuation\">,</span>\n                 c<span class=\"token punctuation\">.</span>city<span class=\"token punctuation\">,</span>\n                 c<span class=\"token punctuation\">.</span>region<span class=\"token punctuation\">,</span>\n                 c<span class=\"token punctuation\">.</span>postal_code<span class=\"token punctuation\">,</span>\n                 c<span class=\"token punctuation\">.</span>country<span class=\"token punctuation\">,</span>\n                 c<span class=\"token punctuation\">.</span>phone<span class=\"token punctuation\">,</span>\n                 c<span class=\"token punctuation\">.</span>fax<span class=\"token punctuation\">,</span>\n                 <span class=\"token punctuation\">(</span><span class=\"token keyword\">SELECT</span> to_json<span class=\"token punctuation\">(</span>array_agg<span class=\"token punctuation\">(</span>to_json<span class=\"token punctuation\">(</span>d<span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span> <span class=\"token keyword\">FROM</span> <span class=\"token punctuation\">(</span><span class=\"token keyword\">SELECT</span> <span class=\"token string\">\"customerTypeId\"</span><span class=\"token punctuation\">,</span> <span class=\"token string\">\"customerDesc\"</span> <span class=\"token keyword\">FROM</span> demographics <span class=\"token keyword\">WHERE</span> demographics<span class=\"token punctuation\">.</span><span class=\"token string\">\"customerId\"</span> <span class=\"token operator\">=</span> c<span class=\"token punctuation\">.</span>customer_id<span class=\"token punctuation\">)</span> d<span class=\"token punctuation\">)</span>\n          <span class=\"token keyword\">FROM</span> customers c<span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span>\n\n     orders<span class=\"token punctuation\">(</span><span class=\"token string\">\"orderId\"</span><span class=\"token punctuation\">,</span> <span class=\"token string\">\"employeeId\"</span><span class=\"token punctuation\">,</span> <span class=\"token string\">\"orderDate\"</span><span class=\"token punctuation\">,</span> <span class=\"token string\">\"requiredDate\"</span><span class=\"token punctuation\">,</span> <span class=\"token string\">\"shippedDate\"</span><span class=\"token punctuation\">,</span> <span class=\"token string\">\"shipVia\"</span><span class=\"token punctuation\">,</span> <span class=\"token string\">\"freight\"</span><span class=\"token punctuation\">,</span>\n            <span class=\"token string\">\"shipName\"</span><span class=\"token punctuation\">,</span> <span class=\"token string\">\"shipAddress\"</span><span class=\"token punctuation\">,</span> <span class=\"token string\">\"shipCity\"</span><span class=\"token punctuation\">,</span> <span class=\"token string\">\"shipRegion\"</span><span class=\"token punctuation\">,</span> <span class=\"token string\">\"shipPostalCode\"</span><span class=\"token punctuation\">,</span> <span class=\"token string\">\"shipCountry\"</span><span class=\"token punctuation\">,</span> <span class=\"token string\">\"orderDetails\"</span><span class=\"token punctuation\">,</span>\n            <span class=\"token string\">\"customer\"</span><span class=\"token punctuation\">)</span> <span class=\"token keyword\">AS</span>\n         <span class=\"token punctuation\">(</span><span class=\"token keyword\">SELECT</span> o<span class=\"token punctuation\">.</span>order_id<span class=\"token punctuation\">,</span>\n                 o<span class=\"token punctuation\">.</span>employee_id<span class=\"token punctuation\">,</span>\n                 o<span class=\"token punctuation\">.</span>order_date<span class=\"token punctuation\">,</span>\n                 o<span class=\"token punctuation\">.</span>required_date<span class=\"token punctuation\">,</span>\n                 o<span class=\"token punctuation\">.</span>shipped_date<span class=\"token punctuation\">,</span>\n                 o<span class=\"token punctuation\">.</span>ship_via<span class=\"token punctuation\">,</span>\n                 o<span class=\"token punctuation\">.</span>freight<span class=\"token punctuation\">,</span>\n                 o<span class=\"token punctuation\">.</span>ship_name<span class=\"token punctuation\">,</span>\n                 o<span class=\"token punctuation\">.</span>ship_address<span class=\"token punctuation\">,</span>\n                 o<span class=\"token punctuation\">.</span>ship_city<span class=\"token punctuation\">,</span>\n                 o<span class=\"token punctuation\">.</span>ship_region<span class=\"token punctuation\">,</span>\n                 o<span class=\"token punctuation\">.</span>ship_postal_code<span class=\"token punctuation\">,</span>\n                 o<span class=\"token punctuation\">.</span>ship_country<span class=\"token punctuation\">,</span>\n                 <span class=\"token punctuation\">(</span><span class=\"token keyword\">SELECT</span> to_json<span class=\"token punctuation\">(</span>array_agg<span class=\"token punctuation\">(</span>to_json<span class=\"token punctuation\">(</span>d<span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span> <span class=\"token keyword\">FROM</span> orderDetails d <span class=\"token keyword\">WHERE</span> d<span class=\"token punctuation\">.</span><span class=\"token string\">\"orderId\"</span> <span class=\"token operator\">=</span> o<span class=\"token punctuation\">.</span>order_id<span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span>\n                 <span class=\"token punctuation\">(</span><span class=\"token keyword\">SELECT</span> to_json<span class=\"token punctuation\">(</span>c<span class=\"token punctuation\">)</span> <span class=\"token keyword\">FROM</span> customers c <span class=\"token keyword\">WHERE</span> c<span class=\"token punctuation\">.</span><span class=\"token string\">\"customerId\"</span> <span class=\"token operator\">=</span> o<span class=\"token punctuation\">.</span>customer_id<span class=\"token punctuation\">)</span>\n          <span class=\"token keyword\">FROM</span> orders o<span class=\"token punctuation\">)</span>\n\n<span class=\"token keyword\">SELECT</span> to_json<span class=\"token punctuation\">(</span>orders<span class=\"token punctuation\">)</span> <span class=\"token keyword\">AS</span> json_body <span class=\"token keyword\">FROM</span> orders <span class=\"token keyword\">WHERE</span> orders<span class=\"token punctuation\">.</span><span class=\"token string\">\"orderId\"</span> <span class=\"token operator\">=</span> ?</code></pre></div>\n<p>The query looks verbose, perhaps a little enigmatic.\nIt is a bit long and therefore it could be overwhelming.\nHowever, on a closer look we could notice it isn't so much complicated - there are few idioms which make the query powerful.</p>\n<p>The good news is that the query generates the exact same JSON as the JPA endpoint provides - it is possible thanks to Postgres’ excellent support for JSON format.\nOur case is not sophisticated though - single <code class=\"language-text\">to_json</code> function is enough to deal with JSON objects and arrays.</p>\n<p>One can notice how the nesting has been realized: how to nest JSON objects and JSON arrays, e.g. the <code class=\"language-text\">orderDetails</code> or the <code class=\"language-text\">customer</code> into <code class=\"language-text\">order</code>).\nThe simple idiom (accordingly <code class=\"language-text\">to_json(...)</code> or <code class=\"language-text\">to_json(array_agg(to_json(...)))</code>) does the job.</p>\n<p>The database query could be adapted according to the caller needs - the response can be shrinked, making the query simpler and - most probably - even more effective.</p>\n<p>Worth noticing is that the join table <code class=\"language-text\">customer_customer_demo</code> has been mitigated in the end result, just like the JPA version does by using <code class=\"language-text\">@ManyToMany</code>.</p>\n<hr>\n<blockquote>\n<p><em>The query is flexible enough to substitute all JPA features we need.</em></p>\n</blockquote>\n<hr>\n<p>I want also emphasize the fact of CTE’s being used to decompose the query into logical parts.\nPersonally I find it elegant because it is easy on the eyes and it “scales” - meaning while our case gets more complicated (JSON aggregates more data, becomes deeply nested) our query gets longer instead of getting deeper.\nIf the query grows too long we can simplify it by extracting some it’s parts as database views.</p>\n<p>The CTE has one more advantage here: it gives a control over the keys visible in end resulting JSON (<code class=\"language-text\">order_id</code> becomes <code class=\"language-text\">orderId</code>).</p>\n<p>So we have a nice query which allows us to fetch required data in one hop in a format ready to be consumed by our clients.\nThis means no adjustments are required, therefore the Java implementation can be that easy:</p>\n<div class=\"gatsby-highlight\" data-language=\"java\"><pre class=\"language-java\"><code class=\"language-java\"><span class=\"token annotation punctuation\">@SneakyThrows</span>\n<span class=\"token annotation punctuation\">@GetMapping</span><span class=\"token punctuation\">(</span>path <span class=\"token operator\">=</span> <span class=\"token string\">\"/v2/orders/{order_id}\"</span><span class=\"token punctuation\">,</span>\n            produces <span class=\"token operator\">=</span> APPLICATION_JSON_VALUE<span class=\"token punctuation\">)</span>\n<span class=\"token keyword\">public</span> <span class=\"token class-name\">String</span> <span class=\"token function\">getRawBodyFromDatabase</span><span class=\"token punctuation\">(</span>\n            <span class=\"token annotation punctuation\">@PathVariable</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"order_id\"</span><span class=\"token punctuation\">)</span> <span class=\"token class-name\">Integer</span> orderId<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token keyword\">return</span> jdbcTemplate<span class=\"token punctuation\">.</span><span class=\"token function\">query</span><span class=\"token punctuation\">(</span>JSON_QUERY<span class=\"token punctuation\">,</span> <span class=\"token punctuation\">(</span><span class=\"token class-name\">ResultSet</span> rs<span class=\"token punctuation\">)</span> <span class=\"token operator\">-></span> <span class=\"token punctuation\">{</span>\n        rs<span class=\"token punctuation\">.</span><span class=\"token function\">next</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n        <span class=\"token keyword\">return</span> rs<span class=\"token punctuation\">.</span><span class=\"token function\">getString</span><span class=\"token punctuation\">(</span><span class=\"token number\">1</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span> orderId<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<p>We didn’t use plain JDBC here but a <code class=\"language-text\">JdbcTemplate</code> which has a negligible overhead and it simplifies our code.</p>\n<p>Of course we could achieve similar results using plain JDBC (e.g. by using <code class=\"language-text\">PreparedStatement</code> directly) - without the use of Spring.\nEven then the necessity of extracting only a single field from the result set makes the solution less coarse than using JDBC in a usual way\n(in our case it would require managing at least three result sets).\nAll the complexity has been moved down into the query.</p>\n<h3>But I need a POJO!</h3>\n<p>Some folks could argue “I don’t want the JSON to be directly returned - I definitely need the POJO to make some processing over it”.\nThat's an absolutely fair statement! We can satisfy this requirement as well.</p>\n<p>Let’s point it one more time: our query produces the exact same JSON as the Order JPA entity has been translated into.</p>\n<p>This means we can use the resulting JSON and unmarshall it into an object of class <code class=\"language-text\">Order</code>.\nOf course the object won’t be tracked by the JPA whatsoever but we don’t need these capabilities - remember: we are serving persisted data and not mutating them.</p>\n<div class=\"gatsby-highlight\" data-language=\"java\"><pre class=\"language-java\"><code class=\"language-java\"><span class=\"token annotation punctuation\">@SneakyThrows</span>\n<span class=\"token annotation punctuation\">@GetMapping</span><span class=\"token punctuation\">(</span>path <span class=\"token operator\">=</span> <span class=\"token string\">\"/v3/orders/{order_id}\"</span><span class=\"token punctuation\">,</span>\n            produces <span class=\"token operator\">=</span> APPLICATION_JSON_VALUE<span class=\"token punctuation\">)</span>\n<span class=\"token keyword\">public</span> <span class=\"token class-name\">Order</span> <span class=\"token function\">getEntityNotUsingJpa</span><span class=\"token punctuation\">(</span><span class=\"token annotation punctuation\">@PathVariable</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"order_id\"</span><span class=\"token punctuation\">)</span> <span class=\"token class-name\">Integer</span> orderId<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token keyword\">return</span> jdbcTemplate<span class=\"token punctuation\">.</span><span class=\"token function\">query</span><span class=\"token punctuation\">(</span>JSON_QUERY<span class=\"token punctuation\">,</span> <span class=\"token punctuation\">(</span><span class=\"token class-name\">ResultSet</span> rs<span class=\"token punctuation\">)</span> <span class=\"token operator\">-></span> <span class=\"token punctuation\">{</span>\n        rs<span class=\"token punctuation\">.</span><span class=\"token function\">next</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 function\">unmarshall</span><span class=\"token punctuation\">(</span>rs<span class=\"token punctuation\">.</span><span class=\"token function\">getString</span><span class=\"token punctuation\">(</span><span class=\"token number\">1</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span> <span class=\"token class-name\">Order</span><span class=\"token punctuation\">.</span><span class=\"token keyword\">class</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span> orderId<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span>\n\n<span class=\"token annotation punctuation\">@SneakyThrows</span>\n<span class=\"token keyword\">private</span> <span class=\"token generics\"><span class=\"token punctuation\">&lt;</span><span class=\"token class-name\">T</span><span class=\"token punctuation\">></span></span> <span class=\"token class-name\">T</span> <span class=\"token function\">unmarshall</span><span class=\"token punctuation\">(</span><span class=\"token class-name\">String</span> json_body<span class=\"token punctuation\">,</span> <span class=\"token class-name\">Class</span><span class=\"token generics\"><span class=\"token punctuation\">&lt;</span><span class=\"token class-name\">T</span><span class=\"token punctuation\">></span></span> clazz<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token keyword\">return</span> objectMapper<span class=\"token punctuation\">.</span><span class=\"token function\">readValue</span><span class=\"token punctuation\">(</span>json_body<span class=\"token punctuation\">,</span> clazz<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<p>This version is very similar to V2 but it introduces an additional step of unmarshalling.\nIt is also a great verification step which makes us sure the V1 and V2 results are identical.</p>\n<h3>Measure, measure, measure</h3>\n<p>So how are all the solutions performing?\nWe suspect the V2 version to be faster than the competitors.\nWe are also unsure about the V3 which requires additional unmarshalling phase - could it impact the performance badly?</p>\n<p>The demo project includes a JMeter configuration and a bash script which verifies the configurations.\nThe benchmark is always run against a fresh setup (db + app).\nThe app is running on java 11 with EpsilonGC turned on - this allows us to verify memory consumption of each solution.</p>\n<p>The requests are run in strictly defined sequence, fetching the orders one by one.\nThere’s a prewarming phase which issues 100 requests and then a profiling phase with 20k of requests.</p>\n<p>I have run the benchmark several times on a Macbook Pro 2018, the results are similar on each run.\nHere’s a summary of the most recent run:</p>\n<ul>\n<li>V1 took <strong>1 minute and 25 seconds</strong> to complete the benchmark, the docker container ended up using <strong>1762 MB</strong> (1.641 GiB) of memory.</li>\n<li>V2 took <strong>53 seconds</strong> to complete the benchmark, the docker container ended up using <strong>1710 MB</strong> (1.593 GiB) of memory</li>\n<li>V3 took exactly <strong>1 minute</strong> to complete the benchmark, the docker container ended up using <strong>1758 MB</strong> (1.638 GiB) of memory</li>\n</ul>\n<p>We can see the V2 outperforming the V1 by 32 seconds - that’s <strong>37% improvement</strong>. </p>\n<p><a\n    class=\"gatsby-resp-image-link\"\n    href=\"/static/00907e6fc534a6e242f935607d2ec10b/eb351/benchmark_duration.png\"\n    style=\"display: block\"\n    target=\"_blank\"\n    rel=\"noopener\"\n  >\n    <span\n    class=\"gatsby-resp-image-wrapper\"\n    style=\"position: relative; display: block;  max-width: 590px; margin-left: auto; margin-right: auto;\"\n  >\n    <span\n      class=\"gatsby-resp-image-background-image\"\n      style=\"padding-bottom: 60.79207920792079%; position: relative; bottom: 0; left: 0; background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAMCAYAAABiDJ37AAAACXBIWXMAABYlAAAWJQFJUiTwAAABzklEQVQoz22TW0sbQRTH94tWUAQLRftmaYVC7ScoFgr60qdSaH31QcFCvaGmJoGkiZU21O1GN5vN3i+Znd1/5+zN3cSBH+fMzux/zmVGghhJkpTMDsZCyPIt7u/voKp3GI1UKIos5kOEoV/bS79LsyI8TuAHEYKAp3g+g2l5JZblwzSFtX14HkMQ0p5IHByTJKQiQsYiJDHD74GBl2+aNTbetkpebZJt5z6tNbH++gon56M0IKlINQhCkYKH65sxnr+4xFqNi4q9wOr6A/Sd7NGZmgnO1ozC7/YMdPumwKj42bzz00Dv2hQHW+j/ymy3Z0IbB5lgHMciXZZGyPkU/4YOtrb7c7wndvp496EHWfHw2IhF/SXOOVzXha5P4LmWOF3H0rNTLAqqtmB59QztziS/ATwVKaDSzaXsuAyN5hg/WnpKo/XgX7V1nDc00e1pHlFcXrWiF2nKRBTxdEEdefj05Y9gkCP8r4MM4X/eHWD74w06orZFmjVBStcwDGjaGI5NTdCwsHKCJyvHua2z8DTj+6n6uGDhUJR0MSdGgP3DIQ6+ZewfKqVfsHeg4K/sZoKVlElDmn9q05nOhdV3RDvKmW3boKbSiKIIjuPgP7PRWr4XqQUSAAAAAElFTkSuQmCC'); background-size: cover; display: block;\"\n    ></span>\n    <img\n        class=\"gatsby-resp-image-image\"\n        style=\"width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;box-shadow:inset 0px 0px 0px 400px white;\"\n        alt=\"Benchmark duration in seconds\"\n        title=\"\"\n        src=\"/static/00907e6fc534a6e242f935607d2ec10b/40fad/benchmark_duration.png\"\n        srcset=\"/static/00907e6fc534a6e242f935607d2ec10b/707e9/benchmark_duration.png 148w,\n/static/00907e6fc534a6e242f935607d2ec10b/649e0/benchmark_duration.png 295w,\n/static/00907e6fc534a6e242f935607d2ec10b/40fad/benchmark_duration.png 590w,\n/static/00907e6fc534a6e242f935607d2ec10b/b3fef/benchmark_duration.png 885w,\n/static/00907e6fc534a6e242f935607d2ec10b/eb351/benchmark_duration.png 1010w\"\n        sizes=\"(max-width: 590px) 100vw, 590px\"\n      />\n  </span>\n  </a></p>\n<p>We can notice also a lower memory consumption on the V2 - it used <strong>52 MB</strong> (49 MiB) <strong>less memory</strong> than V1\n(noted the initial app’s memory usage which is 785 MB):</p>\n<p><a\n    class=\"gatsby-resp-image-link\"\n    href=\"/static/b7b44c0c52b828e9c0a6cc8124d4857a/b0617/memory_consumption_table.png\"\n    style=\"display: block\"\n    target=\"_blank\"\n    rel=\"noopener\"\n  >\n    <span\n    class=\"gatsby-resp-image-wrapper\"\n    style=\"position: relative; display: block;  max-width: 590px; margin-left: auto; margin-right: auto;\"\n  >\n    <span\n      class=\"gatsby-resp-image-background-image\"\n      style=\"padding-bottom: 15.815815815815814%; position: relative; bottom: 0; left: 0; background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAADCAYAAACTWi8uAAAACXBIWXMAABYlAAAWJQFJUiTwAAAAoUlEQVQI13WMyw6CMBBF+f9PkhQw3ahAAgYSCAt2ItJaRN5dXKeNceckNzlnXg7nRzDmgvMAQcCID/B9Bs9zrWdZiiSJEUVn5MR5niKOLwjDE/HVuplF5FVVwCnLAk1zw7ouGMe3zTRNXx6xzDOG4YW2vdsdk75X6LrHz6WUkEJg2zY4dV3TUOBfaa3p4UBHAnrfyXco9YSgB4ZNz7iJ2f0AaFLdIFy73HYAAAAASUVORK5CYII='); background-size: cover; display: block;\"\n    ></span>\n    <img\n        class=\"gatsby-resp-image-image\"\n        style=\"width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;box-shadow:inset 0px 0px 0px 400px white;\"\n        alt=\"Memory consumption comparison\"\n        title=\"\"\n        src=\"/static/b7b44c0c52b828e9c0a6cc8124d4857a/40fad/memory_consumption_table.png\"\n        srcset=\"/static/b7b44c0c52b828e9c0a6cc8124d4857a/707e9/memory_consumption_table.png 148w,\n/static/b7b44c0c52b828e9c0a6cc8124d4857a/649e0/memory_consumption_table.png 295w,\n/static/b7b44c0c52b828e9c0a6cc8124d4857a/40fad/memory_consumption_table.png 590w,\n/static/b7b44c0c52b828e9c0a6cc8124d4857a/b3fef/memory_consumption_table.png 885w,\n/static/b7b44c0c52b828e9c0a6cc8124d4857a/b0617/memory_consumption_table.png 999w\"\n        sizes=\"(max-width: 590px) 100vw, 590px\"\n      />\n  </span>\n  </a></p>\n<p><a\n    class=\"gatsby-resp-image-link\"\n    href=\"/static/6101a2054a60731cc34de93dc5d69976/1a868/memory_consumption_chart.png\"\n    style=\"display: block\"\n    target=\"_blank\"\n    rel=\"noopener\"\n  >\n    <span\n    class=\"gatsby-resp-image-wrapper\"\n    style=\"position: relative; display: block;  max-width: 590px; margin-left: auto; margin-right: auto;\"\n  >\n    <span\n      class=\"gatsby-resp-image-background-image\"\n      style=\"padding-bottom: 38.76146788990826%; position: relative; bottom: 0; left: 0; background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAICAYAAAD5nd/tAAAACXBIWXMAABYlAAAWJQFJUiTwAAAB7ElEQVQozzWS228SQRSH+fP8C3z1wTeNIZJWY8Q+tKE1xodqDBa8tS/Gy5OmqTGmSq02xEShGG7lfimwC7uUsOwCy8znsOBJzlzOzHy/OWfGNxMCXdfpahp616Cvtempca1Wxx3b/DfXdZFSYltDtHYb0+hhGxo9XaPVbNJX87n55k3NhddN6QV+D6Cn5mM1flWXCLmIj2wFdye8aeG55Up2GxJtLIkZ8LSKt9dXLfSJHJvcK0Ai3mE1MeVdZsTHY50bGUVaAu2xkhBTgjnJWk7QcSSX4pLTgWRPCV9NLsR9nz/V8EdK3FcKj7dT3DyxCR8ZBLczBEtgOIKRM8Z2HA+4UYGQcn0iufwX0pbKrgPX88sbxr42ub1XY1NtehnNEIg7RH+abEbPuKuAVd2hcd5haKmTzHgQ6/PwyKRruVx5q5HVJrxPDVnZ7yKEAn47bHJrt8qWAj6PLIE/TEI7ee4UVcZikbLjzKsqCEey7ESzGMYYfyBOoThg/6DOeiixAB5+aRB4UWGjDJFwGv+JQ/i7wXo4z6qqq7sEuu7M6x9Fcjx5lqNnOFxb+UVeAT8cNFjbOlVAgc9QC6mSSckSVKsXJNtDzi9c0mddsoMpcvltZjMxfyGKZZNypc90KviTbKlSTGipM+ms7n2rf9gTOwkX5RGhAAAAAElFTkSuQmCC'); background-size: cover; display: block;\"\n    ></span>\n    <img\n        class=\"gatsby-resp-image-image\"\n        style=\"width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;box-shadow:inset 0px 0px 0px 400px white;\"\n        alt=\"Memory consumption comparison\"\n        title=\"\"\n        src=\"/static/6101a2054a60731cc34de93dc5d69976/40fad/memory_consumption_chart.png\"\n        srcset=\"/static/6101a2054a60731cc34de93dc5d69976/707e9/memory_consumption_chart.png 148w,\n/static/6101a2054a60731cc34de93dc5d69976/649e0/memory_consumption_chart.png 295w,\n/static/6101a2054a60731cc34de93dc5d69976/40fad/memory_consumption_chart.png 590w,\n/static/6101a2054a60731cc34de93dc5d69976/b3fef/memory_consumption_chart.png 885w,\n/static/6101a2054a60731cc34de93dc5d69976/301c0/memory_consumption_chart.png 1180w,\n/static/6101a2054a60731cc34de93dc5d69976/1a868/memory_consumption_chart.png 1308w\"\n        sizes=\"(max-width: 590px) 100vw, 590px\"\n      />\n  </span>\n  </a></p>\n<hr>\n<blockquote>\n<p><em>Worth noticing: the V2 version does not leverage Hibernate at all therefore we could minimize the memory footprint even more by excluding the JPA dependencies.</em></p>\n</blockquote>\n<hr>\n<p>Let’s have a look at response times:</p>\n<p><a\n    class=\"gatsby-resp-image-link\"\n    href=\"/static/73c8b2f75166508b24cc53407109875b/13a80/response_time_table.png\"\n    style=\"display: block\"\n    target=\"_blank\"\n    rel=\"noopener\"\n  >\n    <span\n    class=\"gatsby-resp-image-wrapper\"\n    style=\"position: relative; display: block;  max-width: 590px; margin-left: auto; margin-right: auto;\"\n  >\n    <span\n      class=\"gatsby-resp-image-background-image\"\n      style=\"padding-bottom: 11.15107913669065%; position: relative; bottom: 0; left: 0; background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAACCAYAAABYBvyLAAAACXBIWXMAAAsSAAALEgHS3X78AAAAhElEQVQI1z2Muw6CQBBF+f9v0cRlkdibGAE11Gohsj5Acd9ibK6zW1ic3Mk5ySRsdURaNEhLAV61YMUZfHNBRsy3N+R1R63FdLmn1sTGK0H9Su4Atj5hRkyoL3YCyb1/4jEoSG3hxy+kcXgpC2U8rP9EgtNujE7RHZDaYZAG2r7/G378APwJj8zXTZkxAAAAAElFTkSuQmCC'); background-size: cover; display: block;\"\n    ></span>\n    <img\n        class=\"gatsby-resp-image-image\"\n        style=\"width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;box-shadow:inset 0px 0px 0px 400px white;\"\n        alt=\"Response time summary\"\n        title=\"\"\n        src=\"/static/73c8b2f75166508b24cc53407109875b/40fad/response_time_table.png\"\n        srcset=\"/static/73c8b2f75166508b24cc53407109875b/707e9/response_time_table.png 148w,\n/static/73c8b2f75166508b24cc53407109875b/649e0/response_time_table.png 295w,\n/static/73c8b2f75166508b24cc53407109875b/40fad/response_time_table.png 590w,\n/static/73c8b2f75166508b24cc53407109875b/b3fef/response_time_table.png 885w,\n/static/73c8b2f75166508b24cc53407109875b/301c0/response_time_table.png 1180w,\n/static/73c8b2f75166508b24cc53407109875b/13a80/response_time_table.png 1668w\"\n        sizes=\"(max-width: 590px) 100vw, 590px\"\n      />\n  </span>\n  </a></p>\n<p>Once again we are able to notice improved throughput as well as lower latency.</p>\n<p>The plot confirms that as well (cropped for brevity):</p>\n<p><a\n    class=\"gatsby-resp-image-link\"\n    href=\"/static/609ca54ea332fb5f16d9c48de682d24f/4fbf1/response_time_plot.png\"\n    style=\"display: block\"\n    target=\"_blank\"\n    rel=\"noopener\"\n  >\n    <span\n    class=\"gatsby-resp-image-wrapper\"\n    style=\"position: relative; display: block;  max-width: 590px; margin-left: auto; margin-right: auto;\"\n  >\n    <span\n      class=\"gatsby-resp-image-background-image\"\n      style=\"padding-bottom: 42.516069788797054%; position: relative; bottom: 0; left: 0; background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAJCAYAAAAywQxIAAAACXBIWXMAAAsSAAALEgHS3X78AAAA60lEQVQoz6WS227EIAxE+f/v7G4gbIAQrgEyNaTdVdX2oaml0QEsWcPIbF1XpJQQQkCM8TJjTHBagfVhvY7j+Bd7Fe9eA1tro3mJ4wxkt50DR6PW0byq7jNvhgbmfFr/sP1XflZ3GPQM5p1D2zNK9CgpkPwX7dGRfmBwyKREuUVr4LXEZjXYwt+gxA0PfscyT5D8RuSDiqjozS4ztJywLgJ6flFLjoe4w5oFxijalgxWSkGlDGqjHMl2qW1wL3Wwv/sQoc06vlko65PtyUb/3fcysmSzlFDagAsBowT4RI6s/b6bpF938HmPeAfpVL+J2Dl0mAAAAABJRU5ErkJggg=='); background-size: cover; display: block;\"\n    ></span>\n    <img\n        class=\"gatsby-resp-image-image\"\n        style=\"width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;box-shadow:inset 0px 0px 0px 400px white;\"\n        alt=\"Response time percentiles plot\"\n        title=\"\"\n        src=\"/static/609ca54ea332fb5f16d9c48de682d24f/40fad/response_time_plot.png\"\n        srcset=\"/static/609ca54ea332fb5f16d9c48de682d24f/707e9/response_time_plot.png 148w,\n/static/609ca54ea332fb5f16d9c48de682d24f/649e0/response_time_plot.png 295w,\n/static/609ca54ea332fb5f16d9c48de682d24f/40fad/response_time_plot.png 590w,\n/static/609ca54ea332fb5f16d9c48de682d24f/b3fef/response_time_plot.png 885w,\n/static/609ca54ea332fb5f16d9c48de682d24f/4fbf1/response_time_plot.png 1089w\"\n        sizes=\"(max-width: 590px) 100vw, 590px\"\n      />\n  </span>\n  </a></p>\n<p>Personally I am very well satisfied with the V3 results - the memory consumption being at the same level as the JPA it still offers satisfying performance, nearly as good as the V1.\nIt proves that the unmarshalling does not impact the performance as badly as we might expect.</p>\n<p>I really encourage readers try running the benchmark and share their own results!</p>\n<h3>Postgres 12 exclusive</h3>\n<p>Last words about the database: the results are reproducible currently only on Postgres 12,\ndue to <a href=\"/postgres12-a-precious-release\">recent improvements in Common Table Expressions</a>.</p>\n<p>I have had a run on Postgres 11 and the V2’s performance was… horrible - I had to shorten the benchmark 10 times to make it finish in a reasonable time.\nHere are the results I got:</p>\n<p><a\n    class=\"gatsby-resp-image-link\"\n    href=\"/static/1f9adc4fa288d49948eed727adf6be02/25720/postgres11_plot.png\"\n    style=\"display: block\"\n    target=\"_blank\"\n    rel=\"noopener\"\n  >\n    <span\n    class=\"gatsby-resp-image-wrapper\"\n    style=\"position: relative; display: block;  max-width: 590px; margin-left: auto; margin-right: auto;\"\n  >\n    <span\n      class=\"gatsby-resp-image-background-image\"\n      style=\"padding-bottom: 26.254180602006688%; position: relative; bottom: 0; left: 0; background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAFCAYAAABFA8wzAAAACXBIWXMAAAsSAAALEgHS3X78AAAAfElEQVQY06WQ4Q7DIAiEff/HraIIhSvMLWuamP2YyeWLd0KEwsxIicifUvAglForzBx53D2Eh8LDD65yqHA0PA7YqWGecNsoM7d9bitXGSg5LlGLsTt6J4z49od3tVbfWduQXn0KzxnGwJzfXczbXpKZERFEdb17UhY17hdUJojcyMhn+QAAAABJRU5ErkJggg=='); background-size: cover; display: block;\"\n    ></span>\n    <img\n        class=\"gatsby-resp-image-image\"\n        style=\"width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;box-shadow:inset 0px 0px 0px 400px white;\"\n        alt=\"Response time percentiles plot\"\n        title=\"\"\n        src=\"/static/1f9adc4fa288d49948eed727adf6be02/40fad/postgres11_plot.png\"\n        srcset=\"/static/1f9adc4fa288d49948eed727adf6be02/707e9/postgres11_plot.png 148w,\n/static/1f9adc4fa288d49948eed727adf6be02/649e0/postgres11_plot.png 295w,\n/static/1f9adc4fa288d49948eed727adf6be02/40fad/postgres11_plot.png 590w,\n/static/1f9adc4fa288d49948eed727adf6be02/b3fef/postgres11_plot.png 885w,\n/static/1f9adc4fa288d49948eed727adf6be02/301c0/postgres11_plot.png 1180w,\n/static/1f9adc4fa288d49948eed727adf6be02/b5a53/postgres11_plot.png 1770w,\n/static/1f9adc4fa288d49948eed727adf6be02/25720/postgres11_plot.png 1794w\"\n        sizes=\"(max-width: 590px) 100vw, 590px\"\n      />\n  </span>\n  </a></p>\n<p>You can give it a try - the demo app is prepared to allow a quick switch to Postgres 11.</p>\n<h3>Summary</h3>\n<p>The query we have prepared enables fine control over the data being fetched from database.</p>\n<p>We are no longer restricted to tabular data - we could easily fetch complex data graphs, even manipulate them to match the desired format.\nWe did it keeping the solution maintainable and very effective in terms of throughput.</p>\n<p>It is still unknown to me what is the main source of latency in the JPA version: either is it the additional round trips or the internals of Hibernate.\nI see the topic interesting to explore.\nPerhaps some day we’ll get an ORM which is able to load entity graphs using a single query.\nAny Hibernate devs reading here?</p>","fields":{"slug":"/serving-json-from-postgres/","tags":["jdbc","jpa","postgres12","json","spring boot"]}}}]},"authorArticles":{"totalCount":1,"edges":[{"node":{"id":"24fd2709-272a-5811-a69c-7100924de21c","frontmatter":{"category":"Coding","title":"Serving JSON (almost) directly from database","date":"2019-10-29","summary":"Learn how to query JSON data from Postgres 12 to improve Java application's performance.","thumbnail":{"relativePath":"pages/serving-json-from-postgres/liberty.jpg","childImageSharp":{"resolutions":{"base64":"data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAUABQDASIAAhEBAxEB/8QAGAABAAMBAAAAAAAAAAAAAAAAAAIDBAX/xAAUAQEAAAAAAAAAAAAAAAAAAAAA/9oADAMBAAIQAxAAAAHryz0HUYxXEAP/xAAbEAABBAMAAAAAAAAAAAAAAAABAgMSIhAgIf/aAAgBAQABBQJw0SoKxLjVDPT/xAAUEQEAAAAAAAAAAAAAAAAAAAAg/9oACAEDAQE/AR//xAAUEQEAAAAAAAAAAAAAAAAAAAAg/9oACAECAQE/AR//xAAYEAACAwAAAAAAAAAAAAAAAAABIQAQIP/aAAgBAQAGPwJRGzn/xAAaEAEAAwADAAAAAAAAAAAAAAABABEhEDGB/9oACAEBAAE/IVEqq3yWWlcbozCOmOokIz//2gAMAwEAAgADAAAAEOAPAP/EABQRAQAAAAAAAAAAAAAAAAAAACD/2gAIAQMBAT8QH//EABQRAQAAAAAAAAAAAAAAAAAAACD/2gAIAQIBAT8QH//EABwQAQADAQADAQAAAAAAAAAAAAEAETEhQXGhwf/aAAgBAQABPxBIyYq1CL8uc5XU14YIGwTYJTDeFrX2G/k7OwjIAbIBek//2Q==","width":325,"height":325,"src":"/static/e0de7302edcea3d0b0c19a9d147b547a/a2998/liberty.jpg","srcSet":"/static/e0de7302edcea3d0b0c19a9d147b547a/a2998/liberty.jpg 1x,\n/static/e0de7302edcea3d0b0c19a9d147b547a/99cce/liberty.jpg 1.5x,\n/static/e0de7302edcea3d0b0c19a9d147b547a/6e995/liberty.jpg 2x,\n/static/e0de7302edcea3d0b0c19a9d147b547a/968b1/liberty.jpg 3x"}}},"authorName":"Mariusz Nowak","authorDescription":"Mariusz is a Senior Software Engineer at AUTO1 Group.","authorAvatar":null,"headerImage":null},"html":"<p>RESTful API’s are ruling the industry nowadays. They are very often associated with an extremely popular data format - JSON.\nIt is so popular that database creators decided to implement it directly in the database engines.\nAll modern databases offer JSON processing capabilities.\nLet’s have a look and see how can we make use of them to improve our application’s performance.</p>\n<h3>JPA or JDBC?</h3>\n<p>The typical choice for a Java application is to use JPA as the persistence layer abstraction.\nIt became the de-facto standard for a reason - it offers great flexibility and ease of use.\nUnfortunately it doesn't come without a price since we have to pay with degraded performance.</p>\n<p>It is a widely known fact that <strong>ORM’s impact performance</strong>, compared to pure JDBC.\nOn the other hand, relatively few are willing to use plain JDBC, considering the amount of additional work it requires.</p>\n<p>Let me demonstrate how to use JDBC to leverage the performance, with the help of modern Postgres features.</p>\n<h3>Demo time</h3>\n<p>I have prepared a <a href=\"https://github.com/auto1-oss/postgres12-json-demo\">demo application</a> running on Spring Boot which exposes example data from the <a href=\"https://github.com/pthom/northwind_psql\">northwind</a> database.\nThe data are exposed in three different ways.</p>\n<p>The baseline version simply exposes JPA entities:</p>\n<div class=\"gatsby-highlight\" data-language=\"java\"><pre class=\"language-java\"><code class=\"language-java\"><span class=\"token annotation punctuation\">@GetMapping</span><span class=\"token punctuation\">(</span>path <span class=\"token operator\">=</span> <span class=\"token string\">\"/v1/orders/{order_id}\"</span><span class=\"token punctuation\">,</span>\n            produces <span class=\"token operator\">=</span> APPLICATION_JSON_VALUE<span class=\"token punctuation\">)</span>\n<span class=\"token keyword\">public</span> <span class=\"token class-name\">Order</span> <span class=\"token function\">getEntity</span><span class=\"token punctuation\">(</span><span class=\"token annotation punctuation\">@PathVariable</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"order_id\"</span><span class=\"token punctuation\">)</span> <span class=\"token class-name\">Integer</span> orderId<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token keyword\">return</span> orderRepository<span class=\"token punctuation\">.</span><span class=\"token function\">findById</span><span class=\"token punctuation\">(</span>orderId<span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span><span class=\"token function\">orElseThrow</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>The Order entity aggregates data from numerous database tables: <code class=\"language-text\">orders</code>, <code class=\"language-text\">order_details</code>, <code class=\"language-text\">products</code>, <code class=\"language-text\">customers</code>, <code class=\"language-text\">customer_customer_demo</code> and <code class=\"language-text\">customer_demographics</code>.\nYou could check the corresponding JPA mapping <a href=\"https://github.com/auto1-oss/postgres12-json-demo/tree/postgres-12/src/main/java/com/auto1/postgres12/jpa\">here</a>.</p>\n<p>Thanks to the magic of Spring the entity is being translated into a JSON response:</p>\n<div class=\"gatsby-highlight\" data-language=\"json\"><pre class=\"language-json\"><code class=\"language-json\"><span class=\"token punctuation\">{</span>\n  <span class=\"token property\">\"orderId\"</span><span class=\"token operator\">:</span> <span class=\"token number\">10284</span><span class=\"token punctuation\">,</span>\n  <span class=\"token property\">\"employeeId\"</span><span class=\"token operator\">:</span> <span class=\"token number\">4</span><span class=\"token punctuation\">,</span>\n  <span class=\"token property\">\"orderDate\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"1996-08-19\"</span><span class=\"token punctuation\">,</span>\n  <span class=\"token property\">\"requiredDate\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"1996-09-16\"</span><span class=\"token punctuation\">,</span>\n  <span class=\"token property\">\"shippedDate\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"1996-08-27\"</span><span class=\"token punctuation\">,</span>\n  <span class=\"token property\">\"shipVia\"</span><span class=\"token operator\">:</span> <span class=\"token number\">1</span><span class=\"token punctuation\">,</span>\n  <span class=\"token property\">\"freight\"</span><span class=\"token operator\">:</span> <span class=\"token number\">76.56</span><span class=\"token punctuation\">,</span>\n  <span class=\"token property\">\"shipName\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"Lehmanns Marktstand\"</span><span class=\"token punctuation\">,</span>\n  <span class=\"token property\">\"shipAddress\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"Magazinweg 7\"</span><span class=\"token punctuation\">,</span>\n  <span class=\"token property\">\"shipCity\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"Frankfurt a.M.\"</span><span class=\"token punctuation\">,</span>\n  <span class=\"token property\">\"shipRegion\"</span><span class=\"token operator\">:</span> <span class=\"token null keyword\">null</span><span class=\"token punctuation\">,</span>\n  <span class=\"token property\">\"shipPostalCode\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"60528\"</span><span class=\"token punctuation\">,</span>\n  <span class=\"token property\">\"shipCountry\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"Germany\"</span><span class=\"token punctuation\">,</span>\n  <span class=\"token property\">\"orderDetails\"</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">[</span>\n    <span class=\"token punctuation\">{</span>\n      <span class=\"token property\">\"orderId\"</span><span class=\"token operator\">:</span> <span class=\"token number\">10284</span><span class=\"token punctuation\">,</span>\n      <span class=\"token property\">\"productId\"</span><span class=\"token operator\">:</span> <span class=\"token number\">27</span><span class=\"token punctuation\">,</span>\n      <span class=\"token property\">\"product\"</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">{</span>\n        <span class=\"token property\">\"productId\"</span><span class=\"token operator\">:</span> <span class=\"token number\">27</span><span class=\"token punctuation\">,</span>\n        <span class=\"token property\">\"categoryId\"</span><span class=\"token operator\">:</span> <span class=\"token number\">3</span><span class=\"token punctuation\">,</span>\n        <span class=\"token property\">\"supplierId\"</span><span class=\"token operator\">:</span> <span class=\"token number\">11</span><span class=\"token punctuation\">,</span>\n        <span class=\"token property\">\"productName\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"Schoggi Schokolade\"</span><span class=\"token punctuation\">,</span>\n        <span class=\"token property\">\"discontinued\"</span><span class=\"token operator\">:</span> <span class=\"token boolean\">false</span><span class=\"token punctuation\">,</span>\n        <span class=\"token property\">\"quantityPerUnit\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"100 - 100 g pieces\"</span><span class=\"token punctuation\">,</span>\n        <span class=\"token property\">\"unitPrice\"</span><span class=\"token operator\">:</span> <span class=\"token number\">43.9</span><span class=\"token punctuation\">,</span>\n        <span class=\"token property\">\"unitsInStock\"</span><span class=\"token operator\">:</span> <span class=\"token number\">49</span><span class=\"token punctuation\">,</span>\n        <span class=\"token property\">\"unitsOnOrder\"</span><span class=\"token operator\">:</span> <span class=\"token number\">0</span><span class=\"token punctuation\">,</span>\n        <span class=\"token property\">\"reorderLevel\"</span><span class=\"token operator\">:</span> <span class=\"token number\">30</span>\n      <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span>\n      <span class=\"token property\">\"unitPrice\"</span><span class=\"token operator\">:</span> <span class=\"token number\">35.1</span><span class=\"token punctuation\">,</span>\n      <span class=\"token property\">\"quantity\"</span><span class=\"token operator\">:</span> <span class=\"token number\">15</span><span class=\"token punctuation\">,</span>\n      <span class=\"token property\">\"discount\"</span><span class=\"token operator\">:</span> <span class=\"token number\">0.25</span>\n    <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>\n    <span class=\"token punctuation\">{</span>...<span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span>\n    <span class=\"token punctuation\">{</span>...<span class=\"token punctuation\">}</span>\n  <span class=\"token punctuation\">]</span><span class=\"token punctuation\">,</span>\n  <span class=\"token property\">\"customer\"</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token property\">\"customerId\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"LEHMS\"</span><span class=\"token punctuation\">,</span>\n    <span class=\"token property\">\"companyName\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"Lehmanns Marktstand\"</span><span class=\"token punctuation\">,</span>\n    <span class=\"token property\">\"contactName\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"Renate Messner\"</span><span class=\"token punctuation\">,</span>\n    <span class=\"token property\">\"contactTitle\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"Sales Representative\"</span><span class=\"token punctuation\">,</span>\n    <span class=\"token property\">\"address\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"Magazinweg 7\"</span><span class=\"token punctuation\">,</span>\n    <span class=\"token property\">\"city\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"Frankfurt a.M.\"</span><span class=\"token punctuation\">,</span>\n    <span class=\"token property\">\"region\"</span><span class=\"token operator\">:</span> <span class=\"token null keyword\">null</span><span class=\"token punctuation\">,</span>\n    <span class=\"token property\">\"postalCode\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"60528\"</span><span class=\"token punctuation\">,</span>\n    <span class=\"token property\">\"country\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"Germany\"</span><span class=\"token punctuation\">,</span>\n    <span class=\"token property\">\"phone\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"069-0245984\"</span><span class=\"token punctuation\">,</span>\n    <span class=\"token property\">\"fax\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"069-0245874\"</span><span class=\"token punctuation\">,</span>\n    <span class=\"token property\">\"customerDesc\"</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">[</span>\n      <span class=\"token punctuation\">{</span>\n        <span class=\"token property\">\"customerTypeId\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"AAAA\"</span><span class=\"token punctuation\">,</span>\n        <span class=\"token property\">\"customerDesc\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"First demographic\"</span>\n      <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>\n      <span class=\"token punctuation\">{</span>...<span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span>\n      <span class=\"token punctuation\">{</span>...<span class=\"token punctuation\">}</span>\n    <span class=\"token punctuation\">]</span>\n  <span class=\"token punctuation\">}</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<p>The demo project includes the p6spy library which gives an insight into the queries being issued against database.\nTurns out that <strong>three queries</strong> are required to load a particular Order - this means <strong>three database round trips</strong>.</p>\n<p>Of course we can force the ORM to join all the tables and fetch them in one hop, but this seems a not so elegant solution -\nit pushes the ORM to load duplicated data and the necessity of deduplicating them in-memory. Can we do better?</p>\n<h3>JDBC to the rescue</h3>\n<p>JDBC is always a choice if the solution could be expressed via SQL query. Luckily we can create one which matches our case perfectly:</p>\n<div class=\"gatsby-highlight\" data-language=\"sql\"><pre class=\"language-sql\"><code class=\"language-sql\"><span class=\"token keyword\">WITH</span> products<span class=\"token punctuation\">(</span><span class=\"token string\">\"productId\"</span><span class=\"token punctuation\">,</span> <span class=\"token string\">\"categoryId\"</span><span class=\"token punctuation\">,</span> <span class=\"token string\">\"supplierId\"</span><span class=\"token punctuation\">,</span> <span class=\"token string\">\"productName\"</span><span class=\"token punctuation\">,</span> <span class=\"token string\">\"discontinued\"</span><span class=\"token punctuation\">,</span> <span class=\"token string\">\"quantityPerUnit\"</span><span class=\"token punctuation\">,</span>\n              <span class=\"token string\">\"unitPrice\"</span><span class=\"token punctuation\">,</span> <span class=\"token string\">\"unitsInStock\"</span><span class=\"token punctuation\">,</span> <span class=\"token string\">\"unitsOnOrder\"</span><span class=\"token punctuation\">,</span> <span class=\"token string\">\"reorderLevel\"</span><span class=\"token punctuation\">)</span> <span class=\"token keyword\">AS</span>\n         <span class=\"token punctuation\">(</span><span class=\"token keyword\">SELECT</span> p<span class=\"token punctuation\">.</span>product_id<span class=\"token punctuation\">,</span>\n                 p<span class=\"token punctuation\">.</span>category_id<span class=\"token punctuation\">,</span>\n                 p<span class=\"token punctuation\">.</span>supplier_id<span class=\"token punctuation\">,</span>\n                 p<span class=\"token punctuation\">.</span>product_name<span class=\"token punctuation\">,</span>\n                 p<span class=\"token punctuation\">.</span>discontinued::<span class=\"token keyword\">boolean</span><span class=\"token punctuation\">,</span>\n                 p<span class=\"token punctuation\">.</span>quantity_per_unit<span class=\"token punctuation\">,</span>\n                 p<span class=\"token punctuation\">.</span>unit_price<span class=\"token punctuation\">,</span>\n                 p<span class=\"token punctuation\">.</span>units_in_stock<span class=\"token punctuation\">,</span>\n                 p<span class=\"token punctuation\">.</span>units_on_order<span class=\"token punctuation\">,</span>\n                 p<span class=\"token punctuation\">.</span>reorder_level\n          <span class=\"token keyword\">FROM</span> products p<span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span>\n     orderDetails<span class=\"token punctuation\">(</span><span class=\"token string\">\"orderId\"</span><span class=\"token punctuation\">,</span> <span class=\"token string\">\"productId\"</span><span class=\"token punctuation\">,</span> <span class=\"token string\">\"product\"</span><span class=\"token punctuation\">,</span> <span class=\"token string\">\"unitPrice\"</span><span class=\"token punctuation\">,</span> <span class=\"token string\">\"quantity\"</span><span class=\"token punctuation\">,</span> <span class=\"token string\">\"discount\"</span><span class=\"token punctuation\">)</span> <span class=\"token keyword\">AS</span>\n         <span class=\"token punctuation\">(</span><span class=\"token keyword\">SELECT</span> d<span class=\"token punctuation\">.</span>order_id<span class=\"token punctuation\">,</span>\n                 d<span class=\"token punctuation\">.</span>product_id<span class=\"token punctuation\">,</span>\n                 <span class=\"token punctuation\">(</span><span class=\"token keyword\">SELECT</span> to_json<span class=\"token punctuation\">(</span>p<span class=\"token punctuation\">)</span> <span class=\"token keyword\">FROM</span> products p <span class=\"token keyword\">WHERE</span> p<span class=\"token punctuation\">.</span><span class=\"token string\">\"productId\"</span> <span class=\"token operator\">=</span> d<span class=\"token punctuation\">.</span>product_id<span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span>\n                 d<span class=\"token punctuation\">.</span>unit_price<span class=\"token punctuation\">,</span>\n                 d<span class=\"token punctuation\">.</span>quantity<span class=\"token punctuation\">,</span>\n                 d<span class=\"token punctuation\">.</span>discount\n          <span class=\"token keyword\">FROM</span> order_details d<span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span>\n\n     demographics<span class=\"token punctuation\">(</span><span class=\"token string\">\"customerId\"</span><span class=\"token punctuation\">,</span> <span class=\"token string\">\"customerTypeId\"</span><span class=\"token punctuation\">,</span> <span class=\"token string\">\"customerDesc\"</span><span class=\"token punctuation\">)</span> <span class=\"token keyword\">AS</span>\n         <span class=\"token punctuation\">(</span><span class=\"token keyword\">SELECT</span> ccd<span class=\"token punctuation\">.</span>customer_id<span class=\"token punctuation\">,</span>\n                 ccd<span class=\"token punctuation\">.</span>customer_type_id<span class=\"token punctuation\">,</span>\n                 cd<span class=\"token punctuation\">.</span>customer_desc\n          <span class=\"token keyword\">FROM</span> customer_demographics cd\n                   <span class=\"token keyword\">JOIN</span> customer_customer_demo ccd <span class=\"token keyword\">on</span> cd<span class=\"token punctuation\">.</span>customer_type_id <span class=\"token operator\">=</span> ccd<span class=\"token punctuation\">.</span>customer_type_id<span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span>\n     customers<span class=\"token punctuation\">(</span><span class=\"token string\">\"customerId\"</span><span class=\"token punctuation\">,</span> <span class=\"token string\">\"companyName\"</span><span class=\"token punctuation\">,</span> <span class=\"token string\">\"contactName\"</span><span class=\"token punctuation\">,</span> <span class=\"token string\">\"contactTitle\"</span><span class=\"token punctuation\">,</span> <span class=\"token string\">\"address\"</span><span class=\"token punctuation\">,</span> <span class=\"token string\">\"city\"</span><span class=\"token punctuation\">,</span> <span class=\"token string\">\"region\"</span><span class=\"token punctuation\">,</span> <span class=\"token string\">\"postalCode\"</span><span class=\"token punctuation\">,</span>\n               <span class=\"token string\">\"country\"</span><span class=\"token punctuation\">,</span> <span class=\"token string\">\"phone\"</span><span class=\"token punctuation\">,</span> <span class=\"token string\">\"fax\"</span><span class=\"token punctuation\">,</span> <span class=\"token string\">\"customerDesc\"</span><span class=\"token punctuation\">)</span> <span class=\"token keyword\">AS</span>\n         <span class=\"token punctuation\">(</span><span class=\"token keyword\">SELECT</span> c<span class=\"token punctuation\">.</span>customer_id<span class=\"token punctuation\">,</span>\n                 c<span class=\"token punctuation\">.</span>company_name<span class=\"token punctuation\">,</span>\n                 c<span class=\"token punctuation\">.</span>contact_name<span class=\"token punctuation\">,</span>\n                 c<span class=\"token punctuation\">.</span>contact_title<span class=\"token punctuation\">,</span>\n                 c<span class=\"token punctuation\">.</span>address<span class=\"token punctuation\">,</span>\n                 c<span class=\"token punctuation\">.</span>city<span class=\"token punctuation\">,</span>\n                 c<span class=\"token punctuation\">.</span>region<span class=\"token punctuation\">,</span>\n                 c<span class=\"token punctuation\">.</span>postal_code<span class=\"token punctuation\">,</span>\n                 c<span class=\"token punctuation\">.</span>country<span class=\"token punctuation\">,</span>\n                 c<span class=\"token punctuation\">.</span>phone<span class=\"token punctuation\">,</span>\n                 c<span class=\"token punctuation\">.</span>fax<span class=\"token punctuation\">,</span>\n                 <span class=\"token punctuation\">(</span><span class=\"token keyword\">SELECT</span> to_json<span class=\"token punctuation\">(</span>array_agg<span class=\"token punctuation\">(</span>to_json<span class=\"token punctuation\">(</span>d<span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span> <span class=\"token keyword\">FROM</span> <span class=\"token punctuation\">(</span><span class=\"token keyword\">SELECT</span> <span class=\"token string\">\"customerTypeId\"</span><span class=\"token punctuation\">,</span> <span class=\"token string\">\"customerDesc\"</span> <span class=\"token keyword\">FROM</span> demographics <span class=\"token keyword\">WHERE</span> demographics<span class=\"token punctuation\">.</span><span class=\"token string\">\"customerId\"</span> <span class=\"token operator\">=</span> c<span class=\"token punctuation\">.</span>customer_id<span class=\"token punctuation\">)</span> d<span class=\"token punctuation\">)</span>\n          <span class=\"token keyword\">FROM</span> customers c<span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span>\n\n     orders<span class=\"token punctuation\">(</span><span class=\"token string\">\"orderId\"</span><span class=\"token punctuation\">,</span> <span class=\"token string\">\"employeeId\"</span><span class=\"token punctuation\">,</span> <span class=\"token string\">\"orderDate\"</span><span class=\"token punctuation\">,</span> <span class=\"token string\">\"requiredDate\"</span><span class=\"token punctuation\">,</span> <span class=\"token string\">\"shippedDate\"</span><span class=\"token punctuation\">,</span> <span class=\"token string\">\"shipVia\"</span><span class=\"token punctuation\">,</span> <span class=\"token string\">\"freight\"</span><span class=\"token punctuation\">,</span>\n            <span class=\"token string\">\"shipName\"</span><span class=\"token punctuation\">,</span> <span class=\"token string\">\"shipAddress\"</span><span class=\"token punctuation\">,</span> <span class=\"token string\">\"shipCity\"</span><span class=\"token punctuation\">,</span> <span class=\"token string\">\"shipRegion\"</span><span class=\"token punctuation\">,</span> <span class=\"token string\">\"shipPostalCode\"</span><span class=\"token punctuation\">,</span> <span class=\"token string\">\"shipCountry\"</span><span class=\"token punctuation\">,</span> <span class=\"token string\">\"orderDetails\"</span><span class=\"token punctuation\">,</span>\n            <span class=\"token string\">\"customer\"</span><span class=\"token punctuation\">)</span> <span class=\"token keyword\">AS</span>\n         <span class=\"token punctuation\">(</span><span class=\"token keyword\">SELECT</span> o<span class=\"token punctuation\">.</span>order_id<span class=\"token punctuation\">,</span>\n                 o<span class=\"token punctuation\">.</span>employee_id<span class=\"token punctuation\">,</span>\n                 o<span class=\"token punctuation\">.</span>order_date<span class=\"token punctuation\">,</span>\n                 o<span class=\"token punctuation\">.</span>required_date<span class=\"token punctuation\">,</span>\n                 o<span class=\"token punctuation\">.</span>shipped_date<span class=\"token punctuation\">,</span>\n                 o<span class=\"token punctuation\">.</span>ship_via<span class=\"token punctuation\">,</span>\n                 o<span class=\"token punctuation\">.</span>freight<span class=\"token punctuation\">,</span>\n                 o<span class=\"token punctuation\">.</span>ship_name<span class=\"token punctuation\">,</span>\n                 o<span class=\"token punctuation\">.</span>ship_address<span class=\"token punctuation\">,</span>\n                 o<span class=\"token punctuation\">.</span>ship_city<span class=\"token punctuation\">,</span>\n                 o<span class=\"token punctuation\">.</span>ship_region<span class=\"token punctuation\">,</span>\n                 o<span class=\"token punctuation\">.</span>ship_postal_code<span class=\"token punctuation\">,</span>\n                 o<span class=\"token punctuation\">.</span>ship_country<span class=\"token punctuation\">,</span>\n                 <span class=\"token punctuation\">(</span><span class=\"token keyword\">SELECT</span> to_json<span class=\"token punctuation\">(</span>array_agg<span class=\"token punctuation\">(</span>to_json<span class=\"token punctuation\">(</span>d<span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span> <span class=\"token keyword\">FROM</span> orderDetails d <span class=\"token keyword\">WHERE</span> d<span class=\"token punctuation\">.</span><span class=\"token string\">\"orderId\"</span> <span class=\"token operator\">=</span> o<span class=\"token punctuation\">.</span>order_id<span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span>\n                 <span class=\"token punctuation\">(</span><span class=\"token keyword\">SELECT</span> to_json<span class=\"token punctuation\">(</span>c<span class=\"token punctuation\">)</span> <span class=\"token keyword\">FROM</span> customers c <span class=\"token keyword\">WHERE</span> c<span class=\"token punctuation\">.</span><span class=\"token string\">\"customerId\"</span> <span class=\"token operator\">=</span> o<span class=\"token punctuation\">.</span>customer_id<span class=\"token punctuation\">)</span>\n          <span class=\"token keyword\">FROM</span> orders o<span class=\"token punctuation\">)</span>\n\n<span class=\"token keyword\">SELECT</span> to_json<span class=\"token punctuation\">(</span>orders<span class=\"token punctuation\">)</span> <span class=\"token keyword\">AS</span> json_body <span class=\"token keyword\">FROM</span> orders <span class=\"token keyword\">WHERE</span> orders<span class=\"token punctuation\">.</span><span class=\"token string\">\"orderId\"</span> <span class=\"token operator\">=</span> ?</code></pre></div>\n<p>The query looks verbose, perhaps a little enigmatic.\nIt is a bit long and therefore it could be overwhelming.\nHowever, on a closer look we could notice it isn't so much complicated - there are few idioms which make the query powerful.</p>\n<p>The good news is that the query generates the exact same JSON as the JPA endpoint provides - it is possible thanks to Postgres’ excellent support for JSON format.\nOur case is not sophisticated though - single <code class=\"language-text\">to_json</code> function is enough to deal with JSON objects and arrays.</p>\n<p>One can notice how the nesting has been realized: how to nest JSON objects and JSON arrays, e.g. the <code class=\"language-text\">orderDetails</code> or the <code class=\"language-text\">customer</code> into <code class=\"language-text\">order</code>).\nThe simple idiom (accordingly <code class=\"language-text\">to_json(...)</code> or <code class=\"language-text\">to_json(array_agg(to_json(...)))</code>) does the job.</p>\n<p>The database query could be adapted according to the caller needs - the response can be shrinked, making the query simpler and - most probably - even more effective.</p>\n<p>Worth noticing is that the join table <code class=\"language-text\">customer_customer_demo</code> has been mitigated in the end result, just like the JPA version does by using <code class=\"language-text\">@ManyToMany</code>.</p>\n<hr>\n<blockquote>\n<p><em>The query is flexible enough to substitute all JPA features we need.</em></p>\n</blockquote>\n<hr>\n<p>I want also emphasize the fact of CTE’s being used to decompose the query into logical parts.\nPersonally I find it elegant because it is easy on the eyes and it “scales” - meaning while our case gets more complicated (JSON aggregates more data, becomes deeply nested) our query gets longer instead of getting deeper.\nIf the query grows too long we can simplify it by extracting some it’s parts as database views.</p>\n<p>The CTE has one more advantage here: it gives a control over the keys visible in end resulting JSON (<code class=\"language-text\">order_id</code> becomes <code class=\"language-text\">orderId</code>).</p>\n<p>So we have a nice query which allows us to fetch required data in one hop in a format ready to be consumed by our clients.\nThis means no adjustments are required, therefore the Java implementation can be that easy:</p>\n<div class=\"gatsby-highlight\" data-language=\"java\"><pre class=\"language-java\"><code class=\"language-java\"><span class=\"token annotation punctuation\">@SneakyThrows</span>\n<span class=\"token annotation punctuation\">@GetMapping</span><span class=\"token punctuation\">(</span>path <span class=\"token operator\">=</span> <span class=\"token string\">\"/v2/orders/{order_id}\"</span><span class=\"token punctuation\">,</span>\n            produces <span class=\"token operator\">=</span> APPLICATION_JSON_VALUE<span class=\"token punctuation\">)</span>\n<span class=\"token keyword\">public</span> <span class=\"token class-name\">String</span> <span class=\"token function\">getRawBodyFromDatabase</span><span class=\"token punctuation\">(</span>\n            <span class=\"token annotation punctuation\">@PathVariable</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"order_id\"</span><span class=\"token punctuation\">)</span> <span class=\"token class-name\">Integer</span> orderId<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token keyword\">return</span> jdbcTemplate<span class=\"token punctuation\">.</span><span class=\"token function\">query</span><span class=\"token punctuation\">(</span>JSON_QUERY<span class=\"token punctuation\">,</span> <span class=\"token punctuation\">(</span><span class=\"token class-name\">ResultSet</span> rs<span class=\"token punctuation\">)</span> <span class=\"token operator\">-></span> <span class=\"token punctuation\">{</span>\n        rs<span class=\"token punctuation\">.</span><span class=\"token function\">next</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n        <span class=\"token keyword\">return</span> rs<span class=\"token punctuation\">.</span><span class=\"token function\">getString</span><span class=\"token punctuation\">(</span><span class=\"token number\">1</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span> orderId<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<p>We didn’t use plain JDBC here but a <code class=\"language-text\">JdbcTemplate</code> which has a negligible overhead and it simplifies our code.</p>\n<p>Of course we could achieve similar results using plain JDBC (e.g. by using <code class=\"language-text\">PreparedStatement</code> directly) - without the use of Spring.\nEven then the necessity of extracting only a single field from the result set makes the solution less coarse than using JDBC in a usual way\n(in our case it would require managing at least three result sets).\nAll the complexity has been moved down into the query.</p>\n<h3>But I need a POJO!</h3>\n<p>Some folks could argue “I don’t want the JSON to be directly returned - I definitely need the POJO to make some processing over it”.\nThat's an absolutely fair statement! We can satisfy this requirement as well.</p>\n<p>Let’s point it one more time: our query produces the exact same JSON as the Order JPA entity has been translated into.</p>\n<p>This means we can use the resulting JSON and unmarshall it into an object of class <code class=\"language-text\">Order</code>.\nOf course the object won’t be tracked by the JPA whatsoever but we don’t need these capabilities - remember: we are serving persisted data and not mutating them.</p>\n<div class=\"gatsby-highlight\" data-language=\"java\"><pre class=\"language-java\"><code class=\"language-java\"><span class=\"token annotation punctuation\">@SneakyThrows</span>\n<span class=\"token annotation punctuation\">@GetMapping</span><span class=\"token punctuation\">(</span>path <span class=\"token operator\">=</span> <span class=\"token string\">\"/v3/orders/{order_id}\"</span><span class=\"token punctuation\">,</span>\n            produces <span class=\"token operator\">=</span> APPLICATION_JSON_VALUE<span class=\"token punctuation\">)</span>\n<span class=\"token keyword\">public</span> <span class=\"token class-name\">Order</span> <span class=\"token function\">getEntityNotUsingJpa</span><span class=\"token punctuation\">(</span><span class=\"token annotation punctuation\">@PathVariable</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"order_id\"</span><span class=\"token punctuation\">)</span> <span class=\"token class-name\">Integer</span> orderId<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token keyword\">return</span> jdbcTemplate<span class=\"token punctuation\">.</span><span class=\"token function\">query</span><span class=\"token punctuation\">(</span>JSON_QUERY<span class=\"token punctuation\">,</span> <span class=\"token punctuation\">(</span><span class=\"token class-name\">ResultSet</span> rs<span class=\"token punctuation\">)</span> <span class=\"token operator\">-></span> <span class=\"token punctuation\">{</span>\n        rs<span class=\"token punctuation\">.</span><span class=\"token function\">next</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 function\">unmarshall</span><span class=\"token punctuation\">(</span>rs<span class=\"token punctuation\">.</span><span class=\"token function\">getString</span><span class=\"token punctuation\">(</span><span class=\"token number\">1</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span> <span class=\"token class-name\">Order</span><span class=\"token punctuation\">.</span><span class=\"token keyword\">class</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span> orderId<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span>\n\n<span class=\"token annotation punctuation\">@SneakyThrows</span>\n<span class=\"token keyword\">private</span> <span class=\"token generics\"><span class=\"token punctuation\">&lt;</span><span class=\"token class-name\">T</span><span class=\"token punctuation\">></span></span> <span class=\"token class-name\">T</span> <span class=\"token function\">unmarshall</span><span class=\"token punctuation\">(</span><span class=\"token class-name\">String</span> json_body<span class=\"token punctuation\">,</span> <span class=\"token class-name\">Class</span><span class=\"token generics\"><span class=\"token punctuation\">&lt;</span><span class=\"token class-name\">T</span><span class=\"token punctuation\">></span></span> clazz<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token keyword\">return</span> objectMapper<span class=\"token punctuation\">.</span><span class=\"token function\">readValue</span><span class=\"token punctuation\">(</span>json_body<span class=\"token punctuation\">,</span> clazz<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<p>This version is very similar to V2 but it introduces an additional step of unmarshalling.\nIt is also a great verification step which makes us sure the V1 and V2 results are identical.</p>\n<h3>Measure, measure, measure</h3>\n<p>So how are all the solutions performing?\nWe suspect the V2 version to be faster than the competitors.\nWe are also unsure about the V3 which requires additional unmarshalling phase - could it impact the performance badly?</p>\n<p>The demo project includes a JMeter configuration and a bash script which verifies the configurations.\nThe benchmark is always run against a fresh setup (db + app).\nThe app is running on java 11 with EpsilonGC turned on - this allows us to verify memory consumption of each solution.</p>\n<p>The requests are run in strictly defined sequence, fetching the orders one by one.\nThere’s a prewarming phase which issues 100 requests and then a profiling phase with 20k of requests.</p>\n<p>I have run the benchmark several times on a Macbook Pro 2018, the results are similar on each run.\nHere’s a summary of the most recent run:</p>\n<ul>\n<li>V1 took <strong>1 minute and 25 seconds</strong> to complete the benchmark, the docker container ended up using <strong>1762 MB</strong> (1.641 GiB) of memory.</li>\n<li>V2 took <strong>53 seconds</strong> to complete the benchmark, the docker container ended up using <strong>1710 MB</strong> (1.593 GiB) of memory</li>\n<li>V3 took exactly <strong>1 minute</strong> to complete the benchmark, the docker container ended up using <strong>1758 MB</strong> (1.638 GiB) of memory</li>\n</ul>\n<p>We can see the V2 outperforming the V1 by 32 seconds - that’s <strong>37% improvement</strong>. </p>\n<p><a\n    class=\"gatsby-resp-image-link\"\n    href=\"/static/00907e6fc534a6e242f935607d2ec10b/eb351/benchmark_duration.png\"\n    style=\"display: block\"\n    target=\"_blank\"\n    rel=\"noopener\"\n  >\n    <span\n    class=\"gatsby-resp-image-wrapper\"\n    style=\"position: relative; display: block;  max-width: 590px; margin-left: auto; margin-right: auto;\"\n  >\n    <span\n      class=\"gatsby-resp-image-background-image\"\n      style=\"padding-bottom: 60.79207920792079%; position: relative; bottom: 0; left: 0; background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAMCAYAAABiDJ37AAAACXBIWXMAABYlAAAWJQFJUiTwAAABzklEQVQoz22TW0sbQRTH94tWUAQLRftmaYVC7ScoFgr60qdSaH31QcFCvaGmJoGkiZU21O1GN5vN3i+Znd1/5+zN3cSBH+fMzux/zmVGghhJkpTMDsZCyPIt7u/voKp3GI1UKIos5kOEoV/bS79LsyI8TuAHEYKAp3g+g2l5JZblwzSFtX14HkMQ0p5IHByTJKQiQsYiJDHD74GBl2+aNTbetkpebZJt5z6tNbH++gon56M0IKlINQhCkYKH65sxnr+4xFqNi4q9wOr6A/Sd7NGZmgnO1ozC7/YMdPumwKj42bzz00Dv2hQHW+j/ymy3Z0IbB5lgHMciXZZGyPkU/4YOtrb7c7wndvp496EHWfHw2IhF/SXOOVzXha5P4LmWOF3H0rNTLAqqtmB59QztziS/ATwVKaDSzaXsuAyN5hg/WnpKo/XgX7V1nDc00e1pHlFcXrWiF2nKRBTxdEEdefj05Y9gkCP8r4MM4X/eHWD74w06orZFmjVBStcwDGjaGI5NTdCwsHKCJyvHua2z8DTj+6n6uGDhUJR0MSdGgP3DIQ6+ZewfKqVfsHeg4K/sZoKVlElDmn9q05nOhdV3RDvKmW3boKbSiKIIjuPgP7PRWr4XqQUSAAAAAElFTkSuQmCC'); background-size: cover; display: block;\"\n    ></span>\n    <img\n        class=\"gatsby-resp-image-image\"\n        style=\"width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;box-shadow:inset 0px 0px 0px 400px white;\"\n        alt=\"Benchmark duration in seconds\"\n        title=\"\"\n        src=\"/static/00907e6fc534a6e242f935607d2ec10b/40fad/benchmark_duration.png\"\n        srcset=\"/static/00907e6fc534a6e242f935607d2ec10b/707e9/benchmark_duration.png 148w,\n/static/00907e6fc534a6e242f935607d2ec10b/649e0/benchmark_duration.png 295w,\n/static/00907e6fc534a6e242f935607d2ec10b/40fad/benchmark_duration.png 590w,\n/static/00907e6fc534a6e242f935607d2ec10b/b3fef/benchmark_duration.png 885w,\n/static/00907e6fc534a6e242f935607d2ec10b/eb351/benchmark_duration.png 1010w\"\n        sizes=\"(max-width: 590px) 100vw, 590px\"\n      />\n  </span>\n  </a></p>\n<p>We can notice also a lower memory consumption on the V2 - it used <strong>52 MB</strong> (49 MiB) <strong>less memory</strong> than V1\n(noted the initial app’s memory usage which is 785 MB):</p>\n<p><a\n    class=\"gatsby-resp-image-link\"\n    href=\"/static/b7b44c0c52b828e9c0a6cc8124d4857a/b0617/memory_consumption_table.png\"\n    style=\"display: block\"\n    target=\"_blank\"\n    rel=\"noopener\"\n  >\n    <span\n    class=\"gatsby-resp-image-wrapper\"\n    style=\"position: relative; display: block;  max-width: 590px; margin-left: auto; margin-right: auto;\"\n  >\n    <span\n      class=\"gatsby-resp-image-background-image\"\n      style=\"padding-bottom: 15.815815815815814%; position: relative; bottom: 0; left: 0; background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAADCAYAAACTWi8uAAAACXBIWXMAABYlAAAWJQFJUiTwAAAAoUlEQVQI13WMyw6CMBBF+f9PkhQw3ahAAgYSCAt2ItJaRN5dXKeNceckNzlnXg7nRzDmgvMAQcCID/B9Bs9zrWdZiiSJEUVn5MR5niKOLwjDE/HVuplF5FVVwCnLAk1zw7ouGMe3zTRNXx6xzDOG4YW2vdsdk75X6LrHz6WUkEJg2zY4dV3TUOBfaa3p4UBHAnrfyXco9YSgB4ZNz7iJ2f0AaFLdIFy73HYAAAAASUVORK5CYII='); background-size: cover; display: block;\"\n    ></span>\n    <img\n        class=\"gatsby-resp-image-image\"\n        style=\"width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;box-shadow:inset 0px 0px 0px 400px white;\"\n        alt=\"Memory consumption comparison\"\n        title=\"\"\n        src=\"/static/b7b44c0c52b828e9c0a6cc8124d4857a/40fad/memory_consumption_table.png\"\n        srcset=\"/static/b7b44c0c52b828e9c0a6cc8124d4857a/707e9/memory_consumption_table.png 148w,\n/static/b7b44c0c52b828e9c0a6cc8124d4857a/649e0/memory_consumption_table.png 295w,\n/static/b7b44c0c52b828e9c0a6cc8124d4857a/40fad/memory_consumption_table.png 590w,\n/static/b7b44c0c52b828e9c0a6cc8124d4857a/b3fef/memory_consumption_table.png 885w,\n/static/b7b44c0c52b828e9c0a6cc8124d4857a/b0617/memory_consumption_table.png 999w\"\n        sizes=\"(max-width: 590px) 100vw, 590px\"\n      />\n  </span>\n  </a></p>\n<p><a\n    class=\"gatsby-resp-image-link\"\n    href=\"/static/6101a2054a60731cc34de93dc5d69976/1a868/memory_consumption_chart.png\"\n    style=\"display: block\"\n    target=\"_blank\"\n    rel=\"noopener\"\n  >\n    <span\n    class=\"gatsby-resp-image-wrapper\"\n    style=\"position: relative; display: block;  max-width: 590px; margin-left: auto; margin-right: auto;\"\n  >\n    <span\n      class=\"gatsby-resp-image-background-image\"\n      style=\"padding-bottom: 38.76146788990826%; position: relative; bottom: 0; left: 0; background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAICAYAAAD5nd/tAAAACXBIWXMAABYlAAAWJQFJUiTwAAAB7ElEQVQozzWS228SQRSH+fP8C3z1wTeNIZJWY8Q+tKE1xodqDBa8tS/Gy5OmqTGmSq02xEShGG7lfimwC7uUsOwCy8znsOBJzlzOzHy/OWfGNxMCXdfpahp616Cvtempca1Wxx3b/DfXdZFSYltDtHYb0+hhGxo9XaPVbNJX87n55k3NhddN6QV+D6Cn5mM1flWXCLmIj2wFdye8aeG55Up2GxJtLIkZ8LSKt9dXLfSJHJvcK0Ai3mE1MeVdZsTHY50bGUVaAu2xkhBTgjnJWk7QcSSX4pLTgWRPCV9NLsR9nz/V8EdK3FcKj7dT3DyxCR8ZBLczBEtgOIKRM8Z2HA+4UYGQcn0iufwX0pbKrgPX88sbxr42ub1XY1NtehnNEIg7RH+abEbPuKuAVd2hcd5haKmTzHgQ6/PwyKRruVx5q5HVJrxPDVnZ7yKEAn47bHJrt8qWAj6PLIE/TEI7ee4UVcZikbLjzKsqCEey7ESzGMYYfyBOoThg/6DOeiixAB5+aRB4UWGjDJFwGv+JQ/i7wXo4z6qqq7sEuu7M6x9Fcjx5lqNnOFxb+UVeAT8cNFjbOlVAgc9QC6mSSckSVKsXJNtDzi9c0mddsoMpcvltZjMxfyGKZZNypc90KviTbKlSTGipM+ms7n2rf9gTOwkX5RGhAAAAAElFTkSuQmCC'); background-size: cover; display: block;\"\n    ></span>\n    <img\n        class=\"gatsby-resp-image-image\"\n        style=\"width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;box-shadow:inset 0px 0px 0px 400px white;\"\n        alt=\"Memory consumption comparison\"\n        title=\"\"\n        src=\"/static/6101a2054a60731cc34de93dc5d69976/40fad/memory_consumption_chart.png\"\n        srcset=\"/static/6101a2054a60731cc34de93dc5d69976/707e9/memory_consumption_chart.png 148w,\n/static/6101a2054a60731cc34de93dc5d69976/649e0/memory_consumption_chart.png 295w,\n/static/6101a2054a60731cc34de93dc5d69976/40fad/memory_consumption_chart.png 590w,\n/static/6101a2054a60731cc34de93dc5d69976/b3fef/memory_consumption_chart.png 885w,\n/static/6101a2054a60731cc34de93dc5d69976/301c0/memory_consumption_chart.png 1180w,\n/static/6101a2054a60731cc34de93dc5d69976/1a868/memory_consumption_chart.png 1308w\"\n        sizes=\"(max-width: 590px) 100vw, 590px\"\n      />\n  </span>\n  </a></p>\n<hr>\n<blockquote>\n<p><em>Worth noticing: the V2 version does not leverage Hibernate at all therefore we could minimize the memory footprint even more by excluding the JPA dependencies.</em></p>\n</blockquote>\n<hr>\n<p>Let’s have a look at response times:</p>\n<p><a\n    class=\"gatsby-resp-image-link\"\n    href=\"/static/73c8b2f75166508b24cc53407109875b/13a80/response_time_table.png\"\n    style=\"display: block\"\n    target=\"_blank\"\n    rel=\"noopener\"\n  >\n    <span\n    class=\"gatsby-resp-image-wrapper\"\n    style=\"position: relative; display: block;  max-width: 590px; margin-left: auto; margin-right: auto;\"\n  >\n    <span\n      class=\"gatsby-resp-image-background-image\"\n      style=\"padding-bottom: 11.15107913669065%; position: relative; bottom: 0; left: 0; background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAACCAYAAABYBvyLAAAACXBIWXMAAAsSAAALEgHS3X78AAAAhElEQVQI1z2Muw6CQBBF+f9v0cRlkdibGAE11Gohsj5Acd9ibK6zW1ic3Mk5ySRsdURaNEhLAV61YMUZfHNBRsy3N+R1R63FdLmn1sTGK0H9Su4Atj5hRkyoL3YCyb1/4jEoSG3hxy+kcXgpC2U8rP9EgtNujE7RHZDaYZAG2r7/G378APwJj8zXTZkxAAAAAElFTkSuQmCC'); background-size: cover; display: block;\"\n    ></span>\n    <img\n        class=\"gatsby-resp-image-image\"\n        style=\"width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;box-shadow:inset 0px 0px 0px 400px white;\"\n        alt=\"Response time summary\"\n        title=\"\"\n        src=\"/static/73c8b2f75166508b24cc53407109875b/40fad/response_time_table.png\"\n        srcset=\"/static/73c8b2f75166508b24cc53407109875b/707e9/response_time_table.png 148w,\n/static/73c8b2f75166508b24cc53407109875b/649e0/response_time_table.png 295w,\n/static/73c8b2f75166508b24cc53407109875b/40fad/response_time_table.png 590w,\n/static/73c8b2f75166508b24cc53407109875b/b3fef/response_time_table.png 885w,\n/static/73c8b2f75166508b24cc53407109875b/301c0/response_time_table.png 1180w,\n/static/73c8b2f75166508b24cc53407109875b/13a80/response_time_table.png 1668w\"\n        sizes=\"(max-width: 590px) 100vw, 590px\"\n      />\n  </span>\n  </a></p>\n<p>Once again we are able to notice improved throughput as well as lower latency.</p>\n<p>The plot confirms that as well (cropped for brevity):</p>\n<p><a\n    class=\"gatsby-resp-image-link\"\n    href=\"/static/609ca54ea332fb5f16d9c48de682d24f/4fbf1/response_time_plot.png\"\n    style=\"display: block\"\n    target=\"_blank\"\n    rel=\"noopener\"\n  >\n    <span\n    class=\"gatsby-resp-image-wrapper\"\n    style=\"position: relative; display: block;  max-width: 590px; margin-left: auto; margin-right: auto;\"\n  >\n    <span\n      class=\"gatsby-resp-image-background-image\"\n      style=\"padding-bottom: 42.516069788797054%; position: relative; bottom: 0; left: 0; background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAJCAYAAAAywQxIAAAACXBIWXMAAAsSAAALEgHS3X78AAAA60lEQVQoz6WS227EIAxE+f/v7G4gbIAQrgEyNaTdVdX2oaml0QEsWcPIbF1XpJQQQkCM8TJjTHBagfVhvY7j+Bd7Fe9eA1tro3mJ4wxkt50DR6PW0byq7jNvhgbmfFr/sP1XflZ3GPQM5p1D2zNK9CgpkPwX7dGRfmBwyKREuUVr4LXEZjXYwt+gxA0PfscyT5D8RuSDiqjozS4ztJywLgJ6flFLjoe4w5oFxijalgxWSkGlDGqjHMl2qW1wL3Wwv/sQoc06vlko65PtyUb/3fcysmSzlFDagAsBowT4RI6s/b6bpF938HmPeAfpVL+J2Dl0mAAAAABJRU5ErkJggg=='); background-size: cover; display: block;\"\n    ></span>\n    <img\n        class=\"gatsby-resp-image-image\"\n        style=\"width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;box-shadow:inset 0px 0px 0px 400px white;\"\n        alt=\"Response time percentiles plot\"\n        title=\"\"\n        src=\"/static/609ca54ea332fb5f16d9c48de682d24f/40fad/response_time_plot.png\"\n        srcset=\"/static/609ca54ea332fb5f16d9c48de682d24f/707e9/response_time_plot.png 148w,\n/static/609ca54ea332fb5f16d9c48de682d24f/649e0/response_time_plot.png 295w,\n/static/609ca54ea332fb5f16d9c48de682d24f/40fad/response_time_plot.png 590w,\n/static/609ca54ea332fb5f16d9c48de682d24f/b3fef/response_time_plot.png 885w,\n/static/609ca54ea332fb5f16d9c48de682d24f/4fbf1/response_time_plot.png 1089w\"\n        sizes=\"(max-width: 590px) 100vw, 590px\"\n      />\n  </span>\n  </a></p>\n<p>Personally I am very well satisfied with the V3 results - the memory consumption being at the same level as the JPA it still offers satisfying performance, nearly as good as the V1.\nIt proves that the unmarshalling does not impact the performance as badly as we might expect.</p>\n<p>I really encourage readers try running the benchmark and share their own results!</p>\n<h3>Postgres 12 exclusive</h3>\n<p>Last words about the database: the results are reproducible currently only on Postgres 12,\ndue to <a href=\"/postgres12-a-precious-release\">recent improvements in Common Table Expressions</a>.</p>\n<p>I have had a run on Postgres 11 and the V2’s performance was… horrible - I had to shorten the benchmark 10 times to make it finish in a reasonable time.\nHere are the results I got:</p>\n<p><a\n    class=\"gatsby-resp-image-link\"\n    href=\"/static/1f9adc4fa288d49948eed727adf6be02/25720/postgres11_plot.png\"\n    style=\"display: block\"\n    target=\"_blank\"\n    rel=\"noopener\"\n  >\n    <span\n    class=\"gatsby-resp-image-wrapper\"\n    style=\"position: relative; display: block;  max-width: 590px; margin-left: auto; margin-right: auto;\"\n  >\n    <span\n      class=\"gatsby-resp-image-background-image\"\n      style=\"padding-bottom: 26.254180602006688%; position: relative; bottom: 0; left: 0; background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAFCAYAAABFA8wzAAAACXBIWXMAAAsSAAALEgHS3X78AAAAfElEQVQY06WQ4Q7DIAiEff/HraIIhSvMLWuamP2YyeWLd0KEwsxIicifUvAglForzBx53D2Eh8LDD65yqHA0PA7YqWGecNsoM7d9bitXGSg5LlGLsTt6J4z49od3tVbfWduQXn0KzxnGwJzfXczbXpKZERFEdb17UhY17hdUJojcyMhn+QAAAABJRU5ErkJggg=='); background-size: cover; display: block;\"\n    ></span>\n    <img\n        class=\"gatsby-resp-image-image\"\n        style=\"width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;box-shadow:inset 0px 0px 0px 400px white;\"\n        alt=\"Response time percentiles plot\"\n        title=\"\"\n        src=\"/static/1f9adc4fa288d49948eed727adf6be02/40fad/postgres11_plot.png\"\n        srcset=\"/static/1f9adc4fa288d49948eed727adf6be02/707e9/postgres11_plot.png 148w,\n/static/1f9adc4fa288d49948eed727adf6be02/649e0/postgres11_plot.png 295w,\n/static/1f9adc4fa288d49948eed727adf6be02/40fad/postgres11_plot.png 590w,\n/static/1f9adc4fa288d49948eed727adf6be02/b3fef/postgres11_plot.png 885w,\n/static/1f9adc4fa288d49948eed727adf6be02/301c0/postgres11_plot.png 1180w,\n/static/1f9adc4fa288d49948eed727adf6be02/b5a53/postgres11_plot.png 1770w,\n/static/1f9adc4fa288d49948eed727adf6be02/25720/postgres11_plot.png 1794w\"\n        sizes=\"(max-width: 590px) 100vw, 590px\"\n      />\n  </span>\n  </a></p>\n<p>You can give it a try - the demo app is prepared to allow a quick switch to Postgres 11.</p>\n<h3>Summary</h3>\n<p>The query we have prepared enables fine control over the data being fetched from database.</p>\n<p>We are no longer restricted to tabular data - we could easily fetch complex data graphs, even manipulate them to match the desired format.\nWe did it keeping the solution maintainable and very effective in terms of throughput.</p>\n<p>It is still unknown to me what is the main source of latency in the JPA version: either is it the additional round trips or the internals of Hibernate.\nI see the topic interesting to explore.\nPerhaps some day we’ll get an ORM which is able to load entity graphs using a single query.\nAny Hibernate devs reading here?</p>","fields":{"slug":"/serving-json-from-postgres/","tags":["jdbc","jpa","postgres12","json","spring boot"]}}}]}},"pageContext":{"slug":"/postgres12-a-precious-release/","tags":["postgres","postgres12","release","sql","cte"],"category":"Coding","author":"Mariusz Nowak","date":"2019-10-29"}}