<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	 xmlns:media="http://search.yahoo.com/mrss/" >

<channel>
	<title>IntelliJ IDEA : IntelliJ IDEA – the Leading IDE for Professional Development in Java and Kotlin | The JetBrains Blog</title>
	<atom:link href="https://blog.jetbrains.com/idea/feed/" rel="self" type="application/rss+xml" />
	<link>https://blog.jetbrains.com</link>
	<description>Developer Tools for Professionals and Teams</description>
	<lastBuildDate>Mon, 13 Apr 2026 07:10:33 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	

<image>
	<url>https://blog.jetbrains.com/wp-content/uploads/2024/01/cropped-mstile-310x310-1-32x32.png</url>
	<title>IntelliJ IDEA : IntelliJ IDEA – the Leading IDE for Professional Development in Java and Kotlin | The JetBrains Blog</title>
	<link>https://blog.jetbrains.com</link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>Using Spring Data JDBC With Kotlin</title>
		<link>https://blog.jetbrains.com/idea/2026/04/using-spring-data-jdbc-with-kotlin/</link>
		
		<dc:creator><![CDATA[Teodor Irkhin]]></dc:creator>
		<pubDate>Thu, 09 Apr 2026 11:46:14 +0000</pubDate>
		<featuredImage>https://blog.jetbrains.com/wp-content/uploads/2026/04/IJ-social-BlogFeatured-1280x720-1-1.png</featuredImage>		<category><![CDATA[features]]></category>
		<category><![CDATA[kotlin]]></category>
		<category><![CDATA[tutorials]]></category>
		<category><![CDATA[jdbc]]></category>
		<category><![CDATA[spring]]></category>
		<guid isPermaLink="false">https://blog.jetbrains.com/?post_type=idea&#038;p=699658</guid>

					<description><![CDATA[This post was written together with&#160;Thorben Janssen, who has more than 20 years of experience with JPA and Hibernate and is the author of “Hibernate Tips: More than 70 Solutions to Common Hibernate Problems” and the JPA newsletter. Spring Data JDBC provides a simple and predictable persistence model. It focuses on aggregate roots, constructor-based mapping, [&#8230;]]]></description>
										<content:encoded><![CDATA[
<p><em>This post was written together with&nbsp;<a href="https://thorben-janssen.com/" target="_blank" rel="noreferrer noopener">Thorben Janssen</a>, who has more than 20 years of experience with JPA and Hibernate and is the author of “Hibernate Tips: More than 70 Solutions to Common Hibernate Problems” and the JPA newsletter.</em></p>



<p>Spring Data JDBC provides a simple and predictable persistence model. It focuses on aggregate roots, constructor-based mapping, and clear rules for reading and writing data. If you enjoy working with explicit data flows and want full control over your SQL, Spring Data JDBC might be the perfect framework for your project.</p>



<p>And with Kotlin, everything becomes so much easier. Its focus on immutability, null safety, and concise data structures aligns nicely with Spring Data JDBC&#8217;s design. In this article, you will see how to model aggregates, store and retrieve data, use <code>value</code> objects, handle child entities, and define custom queries using Kotlin.</p>



<h1 class="wp-block-heading">Kotlin&#8217;s strengths for JDBC-based persistence</h1>



<p>Before looking at concrete examples, it helps to understand why Kotlin fits so well into this programming model.</p>



<p><code>Data</code> classes keep your aggregates concise. They define constructor parameters, implement the <code>equals()</code>, <code>hashCode()</code>, and <code>toString()</code> methods, and encourage immutable states. Spring Data JDBC provides strong support for constructor-based mapping and handles immutable aggregates with ease, significantly reducing boilerplate code.</p>



<p>Kotlin’s type system also reduces many common mistakes. Nullability is explicit, so you can see immediately which fields may not contain a value. Constructor-based mapping becomes more reliable because there is no silent conversion of null values into empty strings or default primitives.</p>



<p>Lightweight <code>value</code> classes allow you to express domain concepts without adding noise. An email address, a customer number, or a price becomes a first-class concept in your model. And Spring Data JDBC can, of course, map them without requiring any additional boilerplate code or mapping annotations.</p>



<p>Kotlin also simplifies custom query projections, because <code>data</code> classes work very well with constructor mapping. Default parameters, named arguments, and collection operations make aggregate updates straightforward.</p>



<p>All these features create a natural fit for Spring Data JDBC and Kotlin.</p>



<h2 class="wp-block-heading">Defining an aggregate root with Kotlin</h2>



<p>An aggregate is a pattern introduced by <a href="https://martinfowler.com/bliki/DDD_Aggregate.html" target="_blank" rel="noopener">domain-driven design (DDD)</a> concepts. It consists of one or more entities that are handled as a unit when reading or writing them to the database. The aggregate root is the primary object of the aggregate. You address it when referencing the aggregate or when fetching it from the database.&nbsp;</p>



<p>Let&#8217;s start with a simple aggregate that only consists of the aggregate root. Each instance is stored as a record in your database whenever you decide to persist or update it. There is no hidden state and no proxying.</p>



<p>The following <code>data</code> class represents a person. The <code>@Table</code> annotation is optional, but it clearly marks the class as an entity. This helps IntelliJ IDEA to provide you with the most suitable tooling when building your persistence layer.</p>



<p>The <code>@Id</code> annotation marks the field as the object’s identifier. The <code>@Sequence</code> annotation is optional and tells Spring Data to retrieve a value from the database sequence when persisting a new object. And because this happens after you created a new Person object in your code, the ID field has to be nullable.</p>



<p>If you want, you can define all other fields as non-nullable.</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">@Table
data class Person(
    @Id
    @Sequence(sequence = "person_seq")
    val id: Long? = null,
    val firstName: String,
    val lastName: String
)</pre>



<p>As you can see in the code snippet, you don’t need to provide any additional mapping annotations. By default, Spring Data JDBC maps the class to a database table with the same name and each field to a column with the same name. You can change this mapping by annotating your class with <code>@Table</code> and a field with <code>@Column</code>. But most teams try to avoid that to keep their entities easy to read and understand.</p>



<p>By default, Spring Data JDBC uses the primary constructor to create and hydrate entity instances. You can also annotate a constructor with <code>@PersistenceCreator</code> if you want Spring Data JDBC to use it instead. This is an excellent match for Kotlin’s <code>data</code> classes, because all non-primary-key fields can be immutable, mandatory, and have default values. This helps you avoid uninitialized properties and the need for no-argument constructors that you might be familiar with in Spring Data JPA and other persistence frameworks.</p>



<p>After you define the aggregate, you have to create a repository to manage it.</p>



<h2 class="wp-block-heading">Creating repositories and defining queries</h2>



<p>Spring Data JDBC uses repository interfaces to define data access operations. The simplest way to define a repository is to extend Spring Data JDBC’s <code>CrudRepository</code>.</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">interface PersonRepository : CrudRepository&lt;Person, Long> {}</pre>



<p>This provides you with basic methods, including <code>save()</code>, <code>findById()</code>, and <code>deleteById()</code>.</p>



<p>You can also add your own queries using Spring Data JDBC’s derived query methods. These are methods whose names describe the query that Spring Data JDBC should execute. The framework parses the method name, creates the appropriate SQL statement, and maps the query result.</p>



<p>And if you need more control over the executed query statement, you can define a method, annotate it with <code>@Query</code>, and provide your own SQL statement. Spring Data JDBC handles the rest!</p>



<p>Here are a few examples.</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">interface PersonRepository : CrudRepository&lt;Person, Long> {
    fun findByLastName(lastName: String): List&lt;Person>

    @Query("select * from Person p where p.last_name = :lastName")
    fun getByLastName(lastName: String): List&lt;Person>
}</pre>



<p>You can also return Kotlin <code>data</code> class projections. This works well when you want to read specific columns but not the entire aggregate, or when you want to transform your data into a different structure.</p>



<p>The following PersonName <code>data</code> class and <code>findPersonNameById</code> repository method show a typical example.&nbsp;</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">data class PersonName(
    val id: Long,
    val name: String
)

interface PersonRepository : CrudRepository&lt;Person, Long> {
    @Query("select p.id, p.first_name || ' ' || p.last_name as name FROM Person p where p.id = :id")
    fun findPersonNameById(id: Long): PersonName
}</pre>



<p>Spring Data JDBC executes the defined query and maps the query result to the constructor parameters of the <code>PersonName</code> class. This keeps the projection code clean and allows you to avoid manual mapping.</p>



<pre class="EnlighterJSRAW" data-enlighter-language="generic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">2025-12-09T21:59:12.572+01:00 DEBUG 7484 --- [SDJWithKotlin] [           main] o.s.jdbc.core.JdbcTemplate               : Executing prepared SQL statement [select p.id, p.first_name || ' ' || p.last_name as name FROM Person p where p.id = ?]
2025-12-09T21:59:12.595+01:00  INFO 7484 --- [SDJWithKotlin] [           main] c.t.j.k.s.SpringDataJdbcKotlinTests      : PersonName(id=401, name=Jane Smith)</pre>



<h2 class="wp-block-heading">Persisting and loading aggregates</h2>



<p>Working with repositories is straightforward. Each call interacts directly with the database. There is no state tracking or implicit updates. This makes the behavior easy to understand and gives you full control over the executed statements.</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">@Service
@Transactional
class PersonService(private val personRepository: PersonRepository) {
    fun createNewPerson(firstName: String, lastName: String): Person {
        // add additional validations and/or logic ...
        return personRepository.save(
            Person(
                firstName = firstName,
                lastName = lastName
            )
        )
    }

    fun updateLastName(id: Long, lastName: String): Person {
        val person = personRepository.findById(id).orElseThrow()
        val updated = person.copy(lastName = lastName)
        return personRepository.save(updated)
    }
}</pre>



<p>The only logic Spring Data JDBC provides when you call the <code>save()</code> method is a check to see if the identifier is <code>null</code>. If it is, the record is inserted. Otherwise, an update is executed. Since all fields are immutable, you’re always working with complete and consistent objects.</p>



<h2 class="wp-block-heading">Using Kotlin value objects in your aggregate</h2>



<p>Real-world aggregates often contain values that deserve their own type. Using Kotlin, you can model them using <code>value</code> classes, and Spring Data JDBC supports them out of the box.</p>



<p>If your <code>value</code> class only wraps one value, you should annotate it with <a href="https://kotlinlang.org/docs/inline-classes.html" target="_blank" rel="noopener">@JvmInline</a>. This activates a Kotlin-specific optimization removing the performance overhead of a wrapper class by replacing it with its inlined value at runtime.</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">@JvmInline
value class Email(val value: String)

data class Person(
    @Id
    @Sequence(sequence = "person_seq")
    val id: Long? = null,
    val firstName: String,
    val lastName: String,
    val email: Email
)</pre>



<p>As you can see, Kotlin’s <code>value</code> and <code>data</code> classes make the code very easy to read and quick to write.&nbsp;</p>



<p>Doing the same in Java requires much more code, an additional mapping annotation and Spring Data JDBC’s embedded entity concept.</p>



<pre class="EnlighterJSRAW" data-enlighter-language="java" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">@Table
public class Person {

    @Id
    @Sequence(sequence = "person_seq")
    private Long id;

    private String firstName;

    private String lastName;

    @Embedded.Nullable
    private Email email;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getFirstName() {
        return firstName;
    }

    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }

    public String getLastName() {
        return lastName;
    }

    public void setLastName(String lastName) {
        this.lastName = lastName;
    }

    public Email getEmail() {
        return email;
    }

    public void setEmail(Email email) {
        this.email = email;
    }
}

public class Email {

    private String email;

    public Email(String email) {
        this.email = email;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }
}</pre>



<p>Java doesn’t know <code>value</code> classes. Spring Data JDBC tries to compensate for this by introducing the concept of an <a href="https://docs.spring.io/spring-data/relational/reference/jdbc/mapping.html#entity-persistence.embedded-entities" target="_blank" rel="noopener">embedded entity</a>.&nbsp;</p>



<p>You define an embedded entity by creating a Java class with a set of properties. In this example, that’s the <code>Email</code> class with its email property. To use the Email class as a property type, you have to annotate it with <code>@Embedded</code>. Spring Data JDBC then applies the same mapping we covered in the example demonstrating Kotlin’s <code>value</code> class. It maps the <code>email</code> field to a database column with the same name, enabling you to use it in all your queries.</p>



<p>So, it looks like you have to write more code and use an embedded entity in Java to get the same result as you got with a simple <code>value</code> class in Kotlin. But it&#8217;s actually worse than that. In Kotlin, you can annotate your simple <code>value</code> classes with <code>@JvmInline</code> and get the previously described optimizations. These don&#8217;t exist in Java. As a result, your embedded class mapping not only requires more code &#8211; it also carries a much greater performance overhead.</p>



<p>Now, let’s get back to our Kotlin-based examples.</p>



<p>Spring Data JDBC maps the value object based on its wrapped value and doesn’t require any additional mapping annotations.</p>



<p>You can even use the <code>value</code> class as a parameter type in your derived or custom queries.</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">interface PersonRepository : CrudRepository&lt;Person, Long> {
    fun findByEmail(email: Email): Person?
}</pre>



<pre class="EnlighterJSRAW" data-enlighter-language="generic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">2025-12-09T22:03:49.340+01:00 DEBUG 14665 --- [SDJWithKotlin] [           main] o.s.jdbc.core.JdbcTemplate               : Executing prepared SQL statement [SELECT "person"."id" AS "id", "person"."email" AS "email", "person"."last_name" AS "last_name", "person"."first_name" AS "first_name" FROM "person" WHERE "person"."email" = ?]
2025-12-09T22:03:49.363+01:00  INFO 14665 --- [SDJWithKotlin] [           main] c.t.j.k.s.SpringDataJdbcKotlinTests      : Person(id=401, firstName=Jane, lastName=Smith, email=Email(value=a@b.com))</pre>



<h2 class="wp-block-heading">Modeling one-to-many relationships</h2>



<p>Aggregates can contain collections of child entities. Spring Data JDBC stores each of these entity types in separate tables.&nbsp;</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">data class Company(
    @Id
    var id: Long,
    val name: String,
    val employees: List&lt;Employee>
)

data class Employee(
    @Id
    var id: Long,
    var name: String
)</pre>



<p>When you read the aggregate, Spring Data JDBC always fetches the entire aggregate with all child entities. And it handles all write operations the same way. When persisting or updating an aggregate, it writes the entire aggregate with all its entities to the database. This fits well with Kotlin’s immutable list types, but requires some attention when defining your aggregates to avoid performance issues.</p>



<h2 class="wp-block-heading">Transactions and practical considerations</h2>



<p>Spring Data JDBC integrates with Spring&#8217;s transaction management. A transactional boundary ensures that all write operations within the aggregate are applied consistently.</p>



<p>Kotlin reduces many typical pitfalls. Properties must be initialized, nullability is clear, and immutable data helps avoid accidental side effects. When updating an aggregate, you create a new instance with the correct state as opposed to modifying an existing one. This results in a predictable and maintainable persistence layer.</p>



<h2 class="wp-block-heading">Conclusion</h2>



<p>Spring Data JDBC offers a clear and simple approach to relational persistence. You work with aggregates that are written and read as complete units, and you always know which statements are executed. Kotlin supports this style through immutable data structures, <code>value</code> classes, nullability rules, and concise syntax.</p>



<p>If you design your aggregates carefully and treat each instance as a complete snapshot of its state, you can build applications that remain easy to understand and maintain. The combination of Spring Data JDBC and Kotlin gives you a persistence stack that stays simple even as your application grows.</p>



<p>To learn more about persistence with Kotlin, check out our two previous articles in this series:&nbsp;&nbsp;&nbsp;</p>



<ul>
<li><a href="https://blog.jetbrains.com/idea/2026/01/how-to-avoid-common-pitfalls-with-jpa-and-kotlin/">How to Avoid Common Pitfalls with JPA and Kotlin</a></li>



<li><a href="https://blog.jetbrains.com/idea/2026/03/using-spring-data-jpa-with-kotlin/">Using Spring Data JPA with Kotlin</a></li>
</ul>



<h2 class="wp-block-heading">About the author</h2>


    <div class="about-author ">
        <div class="about-author__box">
            <div class="row">
                                                            <div class="about-author__box-img">
                            <img style="width:100% !important; height:auto !important; max-width:100% !important;" decoding="async" src="https://blog.jetbrains.com/wp-content/uploads/2025/12/Thorben-Janssen-400x400-1.jpg" alt="" loading="lazy">
                        </div>
                                        <div class="about-author__box-text">
                                                    <h4>Thorben Janssen</h4>
                                                <div class="p-client_container">
<div class="p-ia4_client_container">
<div class="p-ia4_client p-ia4_client--sidebar-wide p-ia4_client--with-split-view-feature">
<div class="p-client_workspace_wrapper" role="tabpanel" aria-label="JetBrains">
<div class="p-client_workspace">
<div class="p-client_workspace__layout">
<div class="p-client_workspace__tabpanel" role="tabpanel" aria-label="DMs">
<div class="enabled-managed-focus-container" role="none">
<div>
<div class="p-view_contents p-view_contents--primary" tabindex="-1" role="dialog" aria-label="Conversation with Teodor Irkhin">
<div class="tabbed_channel__Abx5r">
<div class="tabbed_channel__Abx5r">
<div class="channel_tab_panel__zJ5Bt c-tabs__tab_panel c-tabs__tab_panel--active c-tabs__tab_panel--full_height" role="none" data-qa="tabs_content_container">
<div class="p-file_drag_drop__container">
<div class="p-workspace__primary_view_body">
<div class="p-message_pane p-message_pane--classic-nav p-message_pane--scrollbar-float-adjustment p-message_pane--with-bookmarks-bar" data-qa="message_pane">
<div>
<div id="message-list" role="presentation">
<div id="message-list" class="c-virtual_list c-virtual_list--scrollbar c-message_list c-scrollbar c-scrollbar--fade" role="presentation">
<div class="c-scrollbar__hider" role="presentation" data-qa="slack_kit_scrollbar">
<div class="c-scrollbar__child" role="presentation">
<div class="c-virtual_list__scroll_container" role="presentation" data-qa="slack_kit_list">
<div id="message-list_1766072525.327379" class="c-virtual_list__item" tabindex="0" role="listitem" aria-setsize="-1" data-qa="virtual-list-item" data-item-key="1766072525.327379">
<div class="c-message_kit__background c-message_kit__background--hovered p-message_pane_message__message c-message_kit__message" role="presentation" data-qa="message_container" data-qa-unprocessed="false" data-qa-placeholder="false" data-msg-ts="1766072525.327379" data-msg-channel-id="D072Y30UX54">
<div class="c-message_kit__hover c-message_kit__hover--hovered" role="document" aria-roledescription="message" data-qa-hover="true">
<div class="c-message_kit__actions c-message_kit__actions--above">
<div class="c-message_kit__gutter">
<div class="c-message_kit__gutter__right" role="presentation" data-qa="message_content">
<div class="c-message_kit__blocks c-message_kit__blocks--rich_text">
<div class="c-message__message_blocks c-message__message_blocks--rich_text" data-qa="message-text">
<div class="p-block_kit_renderer" data-qa="block-kit-renderer">
<div class="p-block_kit_renderer__block_wrapper p-block_kit_renderer__block_wrapper--first">
<div class="p-rich_text_block" dir="auto">
<p>Thorben Janssen is a consultant and trainer who helps teams build better persistence layers with JPA and Hibernate. An international speaker with more than 20 years of experience in JPA and Hibernate, Thorben is the author of the best-selling book <i data-stringify-type="italic">Hibernate Tips: More than 70 solutions to common Hibernate problems</i>.</p>
<p>He also writes on thorben-janssen.com about various persistence topics, and to help developers improve their skills, he founded the Persistence Hub.</p>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
                    </div>
                            </div>
        </div>
    </div>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Java Annotated Monthly – April 2026</title>
		<link>https://blog.jetbrains.com/idea/2026/04/java-annotated-monthly-april-2026/</link>
		
		<dc:creator><![CDATA[Irina Mariasova]]></dc:creator>
		<pubDate>Mon, 06 Apr 2026 11:10:42 +0000</pubDate>
		<featuredImage>https://blog.jetbrains.com/wp-content/uploads/2026/04/IJ-social-BlogFeatured-1280x720-1.png</featuredImage>		<category><![CDATA[news]]></category>
		<category><![CDATA[ai]]></category>
		<category><![CDATA[java]]></category>
		<category><![CDATA[java-annotated]]></category>
		<category><![CDATA[java-annotated-monthly]]></category>
		<category><![CDATA[kotlin]]></category>
		<category><![CDATA[spring]]></category>
		<guid isPermaLink="false">https://blog.jetbrains.com/?post_type=idea&#038;p=697934</guid>

					<description><![CDATA[It&#8217;s safe to say March was defined by one thing: Java 26. In this issue of Java Annotated Monthly, we&#8217;ve curated a rich selection of articles to help you get the full picture of the release. Marit van Dijk joins us as the featured guest author, bringing her expertise to help you navigate the changes [&#8230;]]]></description>
										<content:encoded><![CDATA[
<p>It&#8217;s safe to say March was defined by one thing: Java 26. In this issue of Java Annotated Monthly, we&#8217;ve curated a rich selection of articles to help you get the full picture of the release. <a href="https://maritvandijk.com/" target="_blank" rel="noopener">Marit van Dijk</a> joins us as the featured guest author, bringing her expertise to help you navigate the changes with confidence. Alongside our Java 26 coverage, you&#8217;ll find our regular roundup of AI developments, Spring updates, Kotlin news, industry trends, and community reads that caught our eye.</p>



<h2 class="wp-block-heading">Featured Content</h2>


    <div class="about-author ">
        <div class="about-author__box">
            <div class="row">
                                                            <div class="about-author__box-img">
                            <img style="width:100% !important; height:auto !important; max-width:100% !important;" decoding="async" src="https://blog.jetbrains.com/wp-content/uploads/2026/04/1763313006438-1.png" alt="" loading="lazy">
                        </div>
                                        <div class="about-author__box-text">
                                                    <h4>Marit van Dijk</h4>
                                                <p>Marit van Dijk is a Java Champion and Developer Advocate at JetBrains with over 20 years of software development experience. She’s passionate about building great software with great people, and making developers’ lives easier.</p>
                    </div>
                            </div>
        </div>
    </div>



<p>Marit regularly presents at international conferences and shares her expertise through webinars, podcasts, blog posts, videos, and tutorials. She’s also a contributor to the book <a href="https://www.oreilly.com/library/view/97-things-every/9781491952689/" target="_blank" rel="noopener"><em>97 Things Every Java Programmer Should Know</em></a> (O’Reilly Media).</p>



<p>March held a lot of interesting things for Java. First of all, there was the Java 26 release on March 17. You can read all about <a href="https://blog.jetbrains.com/idea/2026/03/java-26-in-intellij-idea/">Java 26 in IntelliJ IDEA </a>on the blog, and find more links on Java 26 in the Java sections below.</p>



<p>Also in March, JavaOne took place in Redwood Shores, USA. During the community keynote, our colleague Anton Arhipov talked about <a href="https://www.youtube.com/live/skc-nIFS-hs?t=5171s" target="_blank" rel="noopener">25 years of IntelliJ IDEA</a>. In case you missed it, we also did a <a href="https://dukescorner.libsyn.com/site/marit-van-dijk-and-anton-arhipov-25-years-of-intellij-idea" target="_blank" rel="noopener">Duke’s Corner podcast</a> and a <a href="https://www.youtube.com/watch?v=Bi3wLP5ZCWw" target="_blank" rel="noopener">Foojay podcast </a>on the same topic. And of course, the <a href="https://www.youtube.com/watch?v=Kourq_Lz03U" target="_blank" rel="noopener">IntelliJ IDEA documentary</a> was released this month. Also at JavaOne, we announced that <a href="https://blog.jetbrains.com/ai/2026/03/koog-comes-to-java/">Koog is coming to Java</a>, if you want to try JetBrains’ <a href="https://www.jetbrains.com/koog/" target="_blank" rel="noopener">Koog</a> AI agent with Java instead of Kotlin.</p>



<p>IntelliJ IDEA 2026.1 was just released. Of course we have Java 26 support from day one, as well as improvements to the debugger for virtual threads, support for new Kotlin features, Spring Data and Spring Debugger features, new AI features, and more. You can read all about it on the <a href="https://blog.jetbrains.com/idea/2026/03/intellij-idea-2026-1/">blog</a> or watch our <a href="https://www.youtube.com/watch?v=FVsMsCFtlOs" target="_blank" rel="noopener">release video</a>.</p>



<p>The release of Java 26 also means that Piotr Przybył and I updated our talk, <a href="https://maritvandijk.com/presentations/modern-java-playful/" target="_blank" rel="noopener"><em>Learning modern Java the playful way</em></a>, for Java 26. You can watch the <a href="https://www.youtube.com/watch?v=6jHZpbLH4WU" target="_blank" rel="noopener">recording from Voxxed Days Amsterdam</a>, or catch us at multiple <a href="https://maritvandijk.com/events/" target="_blank" rel="noopener">events</a> around Europe.&nbsp;</p>



<h2 class="wp-block-heading">Java News</h2>



<p>Check out all the Java news highlights in March:&nbsp;</p>



<ul>
<li>Java News Roundup <a href="https://www.infoq.com/news/2026/03/java-news-roundup-mar02-2026/?utm_campaign=infoq_content&amp;utm_source=infoq&amp;utm_medium=feed&amp;utm_term=global" target="_blank" rel="noopener">1</a>, <a href="https://www.infoq.com/news/2026/03/java-news-roundup-mar09-2026/?utm_campaign=infoq_content&amp;utm_source=infoq&amp;utm_medium=feed&amp;utm_term=global" target="_blank" rel="noopener">2</a>, <a href="https://www.infoq.com/news/2026/03/java-news-roundup-mar16-2026/" target="_blank" rel="noopener">3</a>, <a href="https://www.infoq.com/news/2026/03/java-news-roundup-mar23-2026/?utm_campaign=infoq_content&amp;utm_source=infoq&amp;utm_medium=feed&amp;utm_term=global" target="_blank" rel="noopener">4</a>, <a href="https://www.infoq.com/news/2026/04/java-news-roundup-mar30-2026/" target="_blank" rel="noopener">5</a></li>



<li><a href="https://foojay.io/today/java-26-whats-new/" target="_blank" rel="noopener">Java 26: What’s New?</a></li>



<li><a href="https://inside.java/2026/03/04/jdk-26-http-client/" target="_blank" rel="noopener">HTTP Client Updates in Java 26</a></li>



<li><a href="https://inside.java/2026/03/08/jfokus-java-performance-update/" target="_blank" rel="noopener">Java Performance Update: From JDK 21 to JDK 25</a></li>



<li><a href="https://inside.java/2026/03/10/quality-heads-up/" target="_blank" rel="noopener">Quality Outreach Heads-up &#8211; JDK 27: Removal of ‘java.locale.useOldISOCodes’ System Property</a></li>



<li><a href="https://inside.java/2026/03/12/podcast-051/" target="_blank" rel="noopener">Episode 51 “Unboxing Java 26 for Developers”&nbsp;</a></li>



<li><a href="https://nipafx.dev/talk-java-x" target="_blank" rel="noopener">Java 27 &#8211; Better Language, Better APIs, Better Runtime</a></li>



<li><a href="https://foojay.io/today/foojay-podcast-92/" target="_blank" rel="noopener">Foojay Podcast #92: Java 26 Is Here: What’s New, What’s Gone, and Why It Matters in 2026</a></li>



<li><a href="https://inside.java/2026/03/18/jdk-26-in-2-mins/" target="_blank" rel="noopener">Java 26 in definitely UNDER 3 minutes</a></li>



<li><a href="https://inside.java/2026/03/19/jdk26-security-enhancements/" target="_blank" rel="noopener">JDK 26 Security Enhancements</a></li>
</ul>



<h2 class="wp-block-heading">Java Tutorials and Tips</h2>



<p>You can never have too many tips for getting more out of Java:</p>



<ul>
<li><a href="https://inside.java/2026/03/02/jdk-26-rn-ops/" target="_blank" rel="noopener">Java 26 for DevOps</a></li>



<li><a href="https://hanno.codes/2026/03/17/java-26-is-here/" target="_blank" rel="noopener">Java 26 Is Here, And With It a Solid Foundation for the Future</a></li>



<li><a href="https://pvs-studio.com/en/blog/posts/java/1357/" target="_blank" rel="noopener">Closed-world assumption in Java</a></li>



<li><a href="https://foojay.io/today/java-for-scripting/" target="_blank" rel="noopener">JavaScript (No, Not That One): Modern Automation with Java</a></li>



<li><a href="https://mostlynerdless.de/blog/2026/02/13/redacting-sensitive-data-from-java-flight-recorder-files/" target="_blank" rel="noopener">Redacting Sensitive Data from Java Flight Recorder Files</a></li>



<li><a href="https://foojay.io/today/foojay-podcast-91/" target="_blank" rel="noopener">Foojay Podcast #91: 25 Years of IntelliJ IDEA: The IDE That Grew Up With Java</a></li>



<li><a href="https://maritvandijk.com/vulnerable-api-usage/" target="_blank" rel="noopener">Vulnerable API usage: Is your Java code vulnerable?</a></li>



<li><a href="https://mostlynerdless.de/blog/2026/03/17/java-26-is-boring-and-thats-a-good-thing/" target="_blank" rel="noopener">Java 26 is boring, and that’s a good thing</a></li>



<li><a href="https://inside.java/2026/03/06/podcast-049/" target="_blank" rel="noopener">Episode 49 “LazyConstants in JDK 26”&nbsp;</a></li>



<li><a href="https://donraab.medium.com/empty-should-be-empty-c09e21edc205" target="_blank" rel="noopener">Empty Should be Empty</a></li>



<li><a href="https://www.elastic.co/search-labs/blog/elasticsearch-integration-tests" target="_blank" rel="noopener">Testing Elasticsearch. It just got simpler</a></li>



<li><a href="https://spring.io/blog/2026/03/19/a-bootiful-podcast-cay-horstmann" target="_blank" rel="noopener">A Bootiful Podcast: Cay Horstmann, legendary Java professor, author, lecturer</a>&nbsp;</li>



<li><a href="https://inside.java/2026/03/09/podcast-050/" target="_blank" rel="noopener">Episode 50 “Towards Better Checked Exceptions”&nbsp;</a></li>



<li>How is Leyden improving Java Performance? <a href="https://foojay.io/today/122962/" target="_blank" rel="noopener">1,</a> <a href="https://foojay.io/today/how-is-leyden-improving-java-performance-part-2-of-3/" target="_blank" rel="noopener">2</a>, <a href="https://foojay.io/today/how-is-leyden-improving-java-performance-part-3-of-3/" target="_blank" rel="noopener">3</a></li>



<li><a href="https://jvogel.me/posts/2026/java-is-fast-your-code-might-not-be" target="_blank" rel="noopener">Java Is Fast. Your Code Might Not Be.</a></li>



<li><a href="https://openjdk.org/projects/amber/design-notes/beyond-records" target="_blank" rel="noopener">Data Oriented Programming, Beyond Records&nbsp;</a></li>



<li><a href="https://www.selikoff.net/2026/03/18/javaone-2026-evolving-the-java-language-an-inside-perspective/" target="_blank" rel="noopener">Evolving the Java Language: An Inside Perspective</a></li>



<li><a href="https://www.elastic.co/search-labs/blog/langchain4j-elasticsearch-hybrid-search" target="_blank" rel="noopener">Hybrid search with Java: LangChain4j Elasticsearch integration</a></li>



<li><a href="https://www.selikoff.net/2026/03/19/javaone-2026-secure-coding-guidelines-for-java/" target="_blank" rel="noopener">Secure Coding Guidelines for Java</a></li>



<li><a href="https://www.balarawool.me/Vector-API-Pi-Estimator/" target="_blank" rel="noopener">Estimating value of pi (π) using Monte Carlo Simulation and Vector API</a></li>



<li><a href="https://kpavlov.me/blog/javable/" target="_blank" rel="noopener">Javable: generate Java-friendly wrappers for Kotlin with KSP</a></li>
</ul>



<h2 class="wp-block-heading">Kotlin Corner</h2>



<p>Stay sharp with the latest Kotlin news and practical tips:</p>



<ul>
<li><a href="https://blog.jetbrains.com/kotlin/2026/03/kotlin-2-3-20-released/">Kotlin 2.3.20 Released&nbsp;</a></li>



<li><a href="https://blog.jetbrains.com/amper/2026/03/amper-0-10/">Amper 0.10 – JDK Provisioning, a Maven Converter, Custom Compiler Plugins, and More&nbsp;</a></li>



<li>The <a href="http://klibs.io" target="_blank" rel="noopener">klibs.io</a> source repository was <a href="https://github.com/JetBrains/klibs-io" target="_blank" rel="noopener">made public</a>.</li>



<li><a href="https://proandroiddev.com/building-a-deep-research-agent-with-koog-teaching-your-agent-to-think-in-phases-d5681ea7d237" target="_blank" rel="noopener">Building a Deep Research Agent with Koog — Teaching Your Agent to Think in Phases&nbsp;</a></li>



<li><a href="https://blog.jetbrains.com/ai/2026/03/koog-comes-to-java/">Koog Comes to Java: The Enterprise AI Agent Framework From JetBrains</a></li>



<li><a href="https://blog.jetbrains.com/kotlin/2026/03/introducing-tracy-the-ai-observability-library-for-kotlin/">Introducing Tracy: The AI Observability Library for Kotlin&nbsp;</a></li>



<li><a href="https://blog.jetbrains.com/kotlin/2026/03/kotlinconf-26-speakers-in-conversation-with-josh-long/">KotlinConf’26 Speakers: In Conversation with Josh Long</a>&nbsp;</li>
</ul>



<h2 class="wp-block-heading">AI&nbsp;</h2>



<p>Plenty of AI reads this month. Pick what catches your eye:</p>



<ul>
<li><a href="https://inside.java/2026/03/01/jfr-ai-monitor/" target="_blank" rel="noopener">Intelligent JVM Monitoring: Combining JDK Flight Recorder with AI</a></li>



<li><a href="https://jvmskills.com/" target="_blank" rel="noopener">AI coding skills from the engineers who build the JVM ecosystem</a></li>



<li><a href="https://loiane.com/2026/03/vibe-coding-with-specs-driven-feedback-loops/" target="_blank" rel="noopener">Vibe Coding, But Production-Ready: A Specs-Driven Feedback Loop for AI-Assisted Development</a></li>



<li><a href="https://www.infoq.com/presentations/ai-systems-privacy-security/?utm_campaign=infoq_content&amp;utm_source=infoq&amp;utm_medium=feed&amp;utm_term=global" target="_blank" rel="noopener">Busting AI Myths and Embracing Realities in Privacy &amp; Security</a></li>



<li><a href="https://foojay.io/today/shaping-jakarta-agentic-ai-together-watch-the-open-conversation/" target="_blank" rel="noopener">Shaping Jakarta Agentic AI Together – Watch the Open Conversation</a></li>



<li><a href="https://www.selikoff.net/2026/03/05/devnexus-2026-how-i-automated-my-life-with-mcp-servers/" target="_blank" rel="noopener">how i automated my life with mcp servers</a></li>



<li><a href="https://www.selikoff.net/2026/03/05/devnexus-2026-10-things-i-hate-about-ai/" target="_blank" rel="noopener">10 things i hate about ai</a></li>



<li><a href="https://blog.frankel.ch/writing-agent-skill/" target="_blank" rel="noopener">Writing an agent skill</a>&nbsp;</li>



<li><a href="https://www.selikoff.net/2026/03/06/devnexus-2026-hacking-ai-how-to-survive-the-ai-uprising/" target="_blank" rel="noopener">Hacking AI – How to Survive the AI Uprising</a></li>



<li><a href="https://www.selikoff.net/2026/03/06/devnexus-2026-stop-fighting-your-ai-engineering-prompts-that-actually-work/" target="_blank" rel="noopener">Stop Fighting Your AI: Engineering Prompts That Actually Work</a></li>



<li><a href="https://www.infoq.com/presentations/patterns-ai-native-development/?utm_campaign=infoq_content&amp;utm_source=infoq&amp;utm_medium=feed&amp;utm_term=global" target="_blank" rel="noopener">Four Patterns of AI Native Development</a></li>



<li><a href="https://event-driven.io/en/interactive_rubber_ducking_with_gen_ai/" target="_blank" rel="noopener">Interactive Rubber Ducking with GenAI</a>&nbsp;</li>



<li><a href="https://www.infoq.com/articles/oil-water-moment-ai-architecture/?utm_campaign=infoq_content&amp;utm_source=infoq&amp;utm_medium=feed&amp;utm_term=global" target="_blank" rel="noopener">The Oil and Water Moment in AI Architecture</a></li>



<li><a href="https://www.selikoff.net/2026/03/19/javaone-2026-look-inside-a-large-language-model-to-become-a-better-java-developer/" target="_blank" rel="noopener">Look Inside a Large Language Model to Become a Better Java Developer</a></li>



<li><a href="http://joshondesign.com/2026/03/01/vibecoding_experience" target="_blank" rel="noopener">A Senior Engineer Tries Vibe Coding</a></li>



<li><a href="https://foojay.io/today/how-we-built-a-java-ai-agent-by-connecting-the-dots-the-ecosystem-already-had/" target="_blank" rel="noopener">How We Built a Java AI Agent by Connecting the Dots the Ecosystem Already Had</a>&nbsp;</li>
</ul>



<h2 class="wp-block-heading">Languages, Frameworks, Libraries, and Technologies</h2>



<p>Spring updates and more tech news, all in one place:</p>



<ul>
<li>This Week in Spring <a href="https://spring.io/blog/2026/03/03/this-week-in-spring-march-3rd-2026" target="_blank" rel="noopener">1</a>, <a href="https://spring.io/blog/2026/03/10/this-week-in-spring-march-10th-2026" target="_blank" rel="noopener">2</a>, <a href="https://spring.io/blog/2026/03/17/this-week-in-spring-march-17th-2026" target="_blank" rel="noopener">3</a>, <a href="https://spring.io/blog/2026/03/24/this-week-in-spring-march-24th-2026" target="_blank" rel="noopener">4</a></li>



<li><a href="https://foojay.io/today/data-enrichment-in-mongodb/" target="_blank" rel="noopener">Data Enrichment in MongoDB</a></li>



<li><a href="https://www.youtube.com/watch?v=UqaSWiE076w" target="_blank" rel="noopener">Supercharge your JVM performance with Project Leyden and Spring Boot by Moritz Halbritter</a></li>



<li><a href="https://www.youtube.com/watch?v=D-yp3sB8cu0" target="_blank" rel="noopener">A Typo Led to the Creation of Spring Cloud Contract • Marcin Grzejszczak &amp; Jakub Pilimon • GOTO 2026</a></li>



<li><a href="https://spring.io/blog/2026/03/05/a-bootiful-podcast-jennifer-reif" target="_blank" rel="noopener">A Bootiful Podcast: Neo4j legend Jennifer Reif</a></li>



<li><a href="https://spring.io/blog/2026/03/12/a-bootiful-podcast-soby-chacko" target="_blank" rel="noopener">A Bootiful Podcast: Spring Messaging Legend Soby Chacko</a></li>



<li><a href="https://spring.io/blog/2026/03/18/mcp-apps" target="_blank" rel="noopener">Blending Chat with Rich UIs with Spring AI and MCP Apps</a></li>



<li><a href="https://dzone.com/articles/java-microservicesscs-vs-spring-modulith" target="_blank" rel="noopener">Java Microservices(SCS) vs. Spring Modulith</a></li>



<li><a href="https://spring.io/blog/2026/02/27/moving-beyond-strings-in-spring-data" target="_blank" rel="noopener">Moving beyond Strings in Spring Data</a></li>



<li><a href="https://quarkus.io/blog/new-benchmarks/" target="_blank" rel="noopener">Quarkus has great performance – and we have new evidence</a></li>



<li><a href="https://foojay.io/today/modeling-one-to-many-relationships-in-java-with-mongodb/" target="_blank" rel="noopener">Modeling One-to-Many Relationships in Java with MongoDB</a></li>



<li><a href="https://foojay.io/today/clean-architecture-with-spring-boot-and-mongodb/" target="_blank" rel="noopener">Clean Architecture with Spring Boot and MongoDB</a></li>
</ul>



<h2 class="wp-block-heading">Conferences and Events</h2>



<p>Pick your next events to attend:</p>



<ul>
<li><a href="https://2026.springio.net" target="_blank" rel="noopener">Spring I/O</a> – Barcelona, Spain, April 13–15; Come say hi at the JetBrains booth and join the <a href="https://2026.springio.net/side-events/#community-run" target="_blank" rel="noopener">community run</a>!&nbsp;</li>
</ul>



<figure class="wp-block-image size-full"><a href="https://2026.springio.net/side-events/#community-run" target="_blank" rel="noopener"><img style="width:100% !important; height:auto !important; max-width:100% !important;" decoding="async" fetchpriority="high" src="https://blog.jetbrains.com/wp-content/uploads/2026/04/image-2.jpeg" alt="" class="wp-image-697935"/></a></figure>



<ul>
<li><a href="https://www.javaday.istanbul" target="_blank" rel="noopener">Java Day Istanbul</a> – Istanbul, Türkiye, April 17–18; <a href="https://www.linkedin.com/in/antonarhipov/" target="_blank" rel="noopener">Anton Arhipov</a> is a speaker.&nbsp;&nbsp;</li>



<li><a href="https://2026.europe.jcon.one" target="_blank" rel="noopener">JCON EUROPE</a> – Cologne, Germany, April 20–23; <a href="https://www.linkedin.com/in/maritvandijk/" target="_blank" rel="noopener">Marit van Dijk</a> will talk about learning modern Java the playful way.</li>



<li><a href="https://developersummit.com" target="_blank" rel="noopener">Great International Developer Summit</a> – Bengaluru, India, April 21–24; Join Siva Katamreddy’s talk on Spring AI + MCP.&nbsp;</li>



<li><a href="https://www.devoxx.fr" target="_blank" rel="noopener">Devoxx France</a> – Paris, France, April 22–24; Check out the talks by <a href="https://www.linkedin.com/in/antonarhipov/" target="_blank" rel="noopener">Anton Arhipov</a> and <a href="https://www.linkedin.com/in/maritvandijk/" target="_blank" rel="noopener">Marit van Dijk</a>.&nbsp;&nbsp;</li>



<li><a href="https://devoxx.gr" target="_blank" rel="noopener">Devoxx Greece</a> – Athens, Greece, April 23–25; <a href="https://www.linkedin.com/in/maritvandijk/" target="_blank" rel="noopener">Marit van Dijk</a> is a speaker.&nbsp;</li>



<li><a href="https://romania.voxxeddays.com/voxxed-days-bucharest-2026/" target="_blank" rel="noopener">Voxxed Days Bucharest</a> – Bucharest, Romania, April 28–29; And if you haven’t caught <a href="https://www.linkedin.com/in/maritvandijk/" target="_blank" rel="noopener">Marit van Dijk</a> during this busy month of hers, here’s the last chance to hear her speak in April.</li>
</ul>



<h2 class="wp-block-heading">Culture and Community</h2>



<p>Your go-to section to slow down and think about the industry, self-growth, and more:</p>



<ul>
<li><a href="https://www.infoq.com/podcasts/mindful-leadership/?utm_campaign=infoq_content&amp;utm_source=infoq&amp;utm_medium=feed&amp;utm_term=global" target="_blank" rel="noopener">Mindful Leadership in the Age of AI</a></li>



<li><a href="http://joshondesign.com/2026/03/19/software-joy" target="_blank" rel="noopener">Can we still make software that sparks joy?</a></li>



<li><a href="https://www.infoq.com/podcasts/hidden-driver-engineering-culture/?utm_campaign=infoq_content&amp;utm_source=infoq&amp;utm_medium=feed&amp;utm_term=global" target="_blank" rel="noopener">Information Flow: The Hidden Driver of Engineering Culture</a></li>



<li><a href="https://www.infoq.com/presentations/cultural-alignment/?utm_campaign=infoq_content&amp;utm_source=infoq&amp;utm_medium=feed&amp;utm_term=global" target="_blank" rel="noopener">Beyond the Code: Hiring for Cultural Alignment</a></li>



<li><a href="https://foojay.io/today/language-learning-flashcard-system-part-1/" target="_blank" rel="noopener">Build a Spaced Repetition Flashcard API with Spring Boot &amp; MongoDB (Part 1)</a></li>



<li><a href="https://www.infoq.com/news/2026/03/mf-aiassisted-dev/?utm_campaign=infoq_content&amp;utm_source=infoq&amp;utm_medium=feed&amp;utm_term=global" target="_blank" rel="noopener">Where Do Humans Fit in AI-Assisted Software Development?</a></li>



<li><a href="https://www.infoq.com/news/2026/03/green-IT-AI-impact/?utm_campaign=infoq_content&amp;utm_source=infoq&amp;utm_medium=feed&amp;utm_term=global" target="_blank" rel="noopener">Green IT: How to Reduce the Impact of AI on the Environment</a></li>



<li><a href="https://foojay.io/today/does-language-still-matter-in-the-age-of-ai-yes-but-the-tradeoff-has-changed/" target="_blank" rel="noopener">Does Language Still Matter in the Age of AI? Yes — But the Tradeoff Has Changed</a></li>



<li><a href="https://www.youtube.com/watch?v=Kourq_Lz03U" target="_blank" rel="noopener">IntelliJ IDEA: The Documentary | An origin story</a>&nbsp;</li>



<li><a href="https://blog.frankel.ch/software-architect-elevator/" target="_blank" rel="noopener">The Software Architect Elevator</a>&nbsp;</li>
</ul>



<h2 class="wp-block-heading">And Finally…</h2>



<p>Top picks from the IntelliJ IDEA blog:</p>



<ul>
<li><a href="https://blog.jetbrains.com/idea/2026/03/whats-fixed-intellij-idea-2026-1/">What’s fixed in IntelliJ IDEA 2026.1</a></li>



<li><a href="https://blog.jetbrains.com/idea/2026/03/java-26-in-intellij-idea/">Java 26 in IntelliJ IDEA</a></li>



<li><a href="https://blog.jetbrains.com/idea/2026/03/intellij-idea-s-new-kotlin-coroutine-inspections-explained/">IntelliJ IDEA’s New Kotlin Coroutine Inspections, Explained</a></li>



<li><a href="https://blog.jetbrains.com/ai/2026/03/cursor-joined-the-acp-registry-and-is-now-live-in-your-jetbrains-ide/">Cursor Joined the ACP Registry and Is Now Live in Your JetBrains IDE</a></li>



<li><a href="https://blog.jetbrains.com/platform/2026/03/sunsetting-code-with-me/">Sunsetting Code With Me</a></li>



<li><a href="https://blog.jetbrains.com/ai/2026/03/koog-comes-to-java/">Koog Comes to Java: The Enterprise AI Agent Framework From JetBrains</a></li>



<li><a href="https://blog.jetbrains.com/idea/2026/03/ai-assisted-java-application-development-with-agent-skills/">AI-Assisted Java Application Development with Agent Skills</a></li>



<li><a href="https://blog.jetbrains.com/idea/2026/03/js-ts-free-support/">Core JavaScript and TypeScript Features Become Free in IntelliJ IDEA</a></li>
</ul>



<p>That’s it for today! We’re always collecting ideas for the next Java Annotated Monthly – send us your suggestions via <a href="https://mail.google.com/mail/u/0/?fs=1&amp;tf=cm&amp;source=mailto&amp;to=JAM@jetbrains.com" target="_blank" rel="noopener">email</a> or <a href="https://x.com/intellijidea?ref_src=twsrc%5Egoogle%7Ctwcamp%5Eserp%7Ctwgr%5Eauthor" target="_blank">X</a> by April 20. Don’t forget to check out our archive of <a href="https://www.jetbrains.com/lp/jam/" target="_blank" rel="noopener">past JAM issues</a> for any articles you might have missed!</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Using Spring Data JPA with Kotlin</title>
		<link>https://blog.jetbrains.com/idea/2026/03/using-spring-data-jpa-with-kotlin/</link>
		
		<dc:creator><![CDATA[Teodor Irkhin]]></dc:creator>
		<pubDate>Mon, 30 Mar 2026 11:30:47 +0000</pubDate>
		<featuredImage>https://blog.jetbrains.com/wp-content/uploads/2026/03/IJ-social-BlogFeatured-1280x720-1-4.png</featuredImage>		<category><![CDATA[kotlin]]></category>
		<category><![CDATA[jpa]]></category>
		<category><![CDATA[tutorial]]></category>
		<guid isPermaLink="false">https://blog.jetbrains.com/?post_type=idea&#038;p=693601</guid>

					<description><![CDATA[This post was written together with&#160;Thorben Janssen, who has more than 20 years of experience with JPA and Hibernate and is the author of “Hibernate Tips: More than 70 Solutions to Common Hibernate Problems” and the JPA newsletter. Spring Data JPA is based on the Jakarta Persistence specification and was originally designed for Java. That [&#8230;]]]></description>
										<content:encoded><![CDATA[
<p><em>This post was written together with&nbsp;<a href="https://thorben-janssen.com/" target="_blank" rel="noreferrer noopener">Thorben Janssen</a>, who has more than 20 years of experience with JPA and Hibernate and is the author of “Hibernate Tips: More than 70 Solutions to Common Hibernate Problems” and the JPA newsletter.</em></p>



<p>Spring Data JPA is based on the Jakarta Persistence specification and was originally designed for Java. That often raises the question of whether it is a good fit for Kotlin projects.&nbsp;</p>



<p>The short answer is yes!&nbsp;</p>



<p>You can use Spring Data JPA with Kotlin without any issues and enjoy Kotlin’s compact syntax and language features, like null safety and extension functions, when writing your business code.</p>



<p>And doing all of that is so quick and easy could explained in this short blog post. Let’s use Spring Data JPA with Kotlin to define and use a simple persistence layer.</p>



<h2 class="wp-block-heading"><strong>Required dependencies</strong></h2>



<p>The easiest way to get started is to use the “New Project” wizard in IntelliJ. Once you select Kotlin and Spring Data JPA, the basic setup is done for you. That includes configuring the Kotlin <a href="https://kotlinlang.org/docs/no-arg-plugin.html" target="_blank" rel="noopener">no-arg</a> and <a href="https://kotlinlang.org/docs/all-open-plugin.html#0" target="_blank" rel="noopener">all-open</a> plugins. They ensure that your Kotlin classes fulfill Jakarta Persistence’s requirements for non-final classes and parameterless constructors. You also get the kotlin-reflect dependency, which is required by Spring.</p>



<figure class="wp-block-image size-full"><img style="width:100% !important; height:auto !important; max-width:100% !important;" decoding="async" src="https://blog.jetbrains.com/wp-content/uploads/2026/03/image2-5.png" alt="" class="wp-image-693635"/></figure>



<p>On the next page, you can select the Spring Boot Starter modules and other dependencies you want to use. In this example, that’s Spring Data JPA and the PostgreSQL database driver.</p>



<figure class="wp-block-image size-full"><img style="width:100% !important; height:auto !important; max-width:100% !important;" decoding="async" src="https://blog.jetbrains.com/wp-content/uploads/2026/03/image1-7.png" alt="" class="wp-image-693646"/></figure>



<h3 class="wp-block-heading">Adding Kotlin to an existing project</h3>



<p>If you already have a Java-based Spring Boot project with the required dependencies, you can simply add a Kotlin class to it. Starting with version 2026.1 Intellij IDEA automatically adds the plugins plugin.spring and plugin.jpa to your build configuration and configure the all-open plugin.</p>



<p>In case you’re using an older IDEA version, you have to add the following configuration yourself.</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">plugins {
   kotlin("plugin.spring") version "2.2.20"
   kotlin("plugin.jpa") version "2.2.20"
}

allOpen {
   annotation("jakarta.persistence.Entity")
   annotation("jakarta.persistence.MappedSuperclass")
   annotation("jakarta.persistence.Embeddable")
}</pre>



<h3 class="wp-block-heading">Database and logging configuration</h3>



<p>After defining your project’s dependencies, you need to set up the database connection in your application.properties file, and you can provide your preferred logging configuration.&nbsp;</p>



<p>The following settings connect to a local PostgreSQL database and activate detailed Hibernate logging. The logging configuration instructs Hibernate to log the executed SQL statements and all bind parameter values. This information is extremely helpful during development and debugging, but it generates a lot of output. So, please make sure to use a different logging configuration in production.</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">spring.datasource.url=jdbc:postgresql://localhost:5432/postgres

spring.datasource.username=postgres
spring.datasource.password=postgres

logging.level.root=INFO
logging.level.org.hibernate.SQL=DEBUG
logging.level.org.hibernate.orm.jdbc.bind=TRACE</pre>



<h2 class="wp-block-heading">Modelling entities</h2>



<p>You can then start modeling your entities in Kotlin. The Jakarta Persistence specification defines a few requirements for entity classes. As we explained in a <a href="https://blog.jetbrains.com/idea/2026/01/how-to-avoid-common-pitfalls-with-jpa-and-kotlin/">recent article on common best practices</a>, some of these requirements don’t align well with Kotlin’s data classes. But you will not run into any issues and enjoy Kotlin’s concise syntax if you define your entity classes as regular Kotlin classes and annotate the fields you want to persist.</p>



<p>It’s a general best practice to avoid exposing your entity classes and their technical dependencies in your API. Most teams introduce a second non-entity representation of their data for that. Using Kotlin, you can easily model those classes as a data class. Doing that requires additional mapping code to convert your data between the different formats. You could, of course, do that in your business code. But it’s much more comfortable to add a set of converter functions to your entity class or select the data class directly from the database. You will see an example of the second approach later in this article. Let’s concentrate on the entity class for now.</p>



<p>Here is a simple Person entity. It maps the person’s first and last name, along with a many-to-one relationship to the company they work for.&nbsp;</p>



<p>The PersonData class represents the same information. You can use it in your API without exposing any technical details of your persistence layer. To make using this class as comfortable as possible, the Person entity class provides 2 functions with the required mapping code.</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">@Entity
class Person(
    @Id
    @GeneratedValue
    var id: Long? = null,

    var firstName: String? = null,

    var lastName: String? = null,

    @ManyToOne(fetch = FetchType.LAZY)
    var company: Company? = null,

    @Version
    var version: Integer? = null
) {
    fun createPersonData(): PersonData {
        return PersonData(
            id = id!!,
            firstName = firstName ?: "",
            lastName = lastName ?: "",
            version = version
        )
    }

    companion object {
        fun createPersonFromData(data: PersonData): Person {
            return Person(
                id = data.id,
                firstName = data.firstName,
                lastName = data.lastName,
                version = data.version
            )
        }
    }
}

data class PersonData(
    val id: Long,
    val firstName: String,
    val lastName: String,
    val version: Int
)</pre>



<p>The functions&nbsp;</p>



<p>The Company entity follows the same approach:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">@Entity
class Company(
    @Id
    @GeneratedValue
    var id: Long? = null,

    var name: String = "default",

    @Version
    var version: Integer? = null
)</pre>



<p>After you modeled your entity classes, you can start defining your repositories.</p>



<h2 class="wp-block-heading">Designing and using a repository</h2>



<p>Spring Data JPA’s repository abstraction works the same way in Kotlin as it does in Java. You extend one of the provided repository interfaces, such as JpaRepository or CrudRepository, and Spring Data provides you with an implementation.&nbsp;</p>



<p>These repositories define a set of standard methods for fetching entities by primary key, persisting new entities, and removing existing ones. They also integrate with Spring’s transaction handling, so that you can use the <a href="https://www.marcobehler.com/guides/spring-transaction-management-transactional-in-depth" target="_blank" rel="noopener">@Transactional annotation</a> on your business or API layer to define the transaction handling.</p>



<p>Here is an example of a simple PersonRepository definition. It inherits all standard methods defined by the JpaRepository. Let’s see how to add your own query methods in one of the following examples.</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">interface PersonRepository : JpaRepository&lt;Person, Long> {}</pre>



<p>To make it even easier, IntelliJ IDEA can create the repository for you automatically. Just start typing repository name in the service and IDEA will suggest creating it:</p>



<figure class="wp-block-image size-full"><img style="width:100% !important; height:auto !important; max-width:100% !important;" decoding="async" loading="lazy" src="https://blog.jetbrains.com/wp-content/uploads/2026/03/image-47.png" alt="" class="wp-image-693607"/></figure>



<p>With this repository in place, you can focus on your business logic. That’s especially convenient in Kotlin because constructor injection and concise function definitions keep your classes short and focused.&nbsp;</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">@Component
@Transactional
class PersonController (
   private val personRepository: PersonRepository) {
   fun createNewPerson(person : Person): Person {
       // add additional validations and/or logic ...
       return personRepository.save(person)
   }
}</pre>



<p>In this example, Spring injects a PersonRepository instance and joins an active transaction or starts a new one before entering the createNewPerson method. If it started a new transaction, it also commits it after completing this method call. And the PersonRepository, together with the Jakarta Persistence implementation, provides the required code to create and execute a SQL INSERT statement that stores the provided Person object in the database.</p>



<pre class="EnlighterJSRAW" data-enlighter-language="generic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">2025-11-16T16:02:53.988+01:00 DEBUG 10104 --- [SDJWithKotlin] [           main] org.hibernate.SQL                        : select next value for person_seq
2025-11-16T16:02:54.012+01:00 DEBUG 10104 --- [SDJWithKotlin] [           main] org.hibernate.SQL                        : insert into person (company_id,first_name,last_name,version,id) values (?,?,?,?,?)
2025-11-16T16:02:54.014+01:00 TRACE 10104 --- [SDJWithKotlin] [           main] org.hibernate.orm.jdbc.bind              : binding parameter (1:BIGINT) &lt;- [null]
2025-11-16T16:02:54.014+01:00 TRACE 10104 --- [SDJWithKotlin] [           main] org.hibernate.orm.jdbc.bind              : binding parameter (2:VARCHAR) &lt;- [John]
2025-11-16T16:02:54.014+01:00 TRACE 10104 --- [SDJWithKotlin] [           main] org.hibernate.orm.jdbc.bind              : binding parameter (3:VARCHAR) &lt;- [Doe]
2025-11-16T16:02:54.014+01:00 TRACE 10104 --- [SDJWithKotlin] [           main] org.hibernate.orm.jdbc.bind              : binding parameter (4:INTEGER) &lt;- [0]
2025-11-16T16:02:54.015+01:00 TRACE 10104 --- [SDJWithKotlin] [           main] org.hibernate.orm.jdbc.bind              : binding parameter (5:BIGINT) &lt;- [2]
</pre>



<p>You might know all of this from using Spring Data JPA with Java. Kotlin does not change any of this behavior, and you also get all the benefits from using Kotlin when implementing your business logic.</p>



<p>Let’s take a look at another example.</p>



<p>Fetching and updating an existing entity follows the same pattern. The updateLastName function loads the entity by its primary key and changes the lastName. That’s all you have to do. The Jakarta Persistence implementation finds that modification during its next <a href="https://www.baeldung.com/java-hibernate-entity-dirty-check" target="_blank" rel="noopener">dirty check</a> and updates the database automatically.</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">@Component
@Transactional
class PersonController (
   private val personRepository: PersonRepository) {
   fun updateLastName(id : Long, lastName : String): Person {
       var person = personRepository.findById(id).orElseThrow()
       person.lastName = lastName
       return person
   }
}</pre>



<p>As you can see, Kotlin’s concise syntax helps keep the business logic easy to read, and Spring handles all the boilerplate code for you. That makes implementing your application very comfortable.</p>



<h2 class="wp-block-heading">Adding your own queries</h2>



<p>In addition to the standard methods provided by Spring Data JPA’s repositories, you need to define queries that fetch the data used in your business code. You can do that in 2 ways, both of which work fine with Kotlin.&nbsp;</p>



<p>The first and most convenient option is to use <a href="https://docs.spring.io/spring-data/jpa/reference/jpa/query-methods.html" target="_blank" rel="noopener">derived query methods</a>. Spring analyzes the method name, derives the corresponding JPQL query, and binds the method parameter values. This is a good choice when your query is simple and only requires one or two bind parameters.</p>



<p>You can add a derived query method directly to your repository. Or In IDEA, you can start typing a desired method name and use autocompletion to have it automatically added to your repository.</p>



<p>You can see a typical example in the following code snippet. The findByLastName method fetches all Person entities with a lastName equal to the provided one.</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">interface PersonRepository : JpaRepository&lt;Person, Long> {
   fun findByLastName(lastName: String): List&lt;Person>
}</pre>



<p>If your query becomes more complex, you should instead annotate your repository method with a <a href="https://thorben-janssen.com/spring-data-jpa-query-annotation/" target="_blank" rel="noopener">@Query annotation</a>. That allows you to write your own <a href="https://thorben-janssen.com/jpql/" target="_blank" rel="noopener">JPQL query</a> and gives you full control over the executed statement. You can use joins, grouping, or any other JPQL feature you need.</p>



<p>Here you can see the same query statement as in the previous example. But this time, using a <code>@Query</code> annotation instead of Spring Data’s derived query feature.</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">interface PersonRepository : JpaRepository&lt;Person, Long> {
   @Query("select p from Person p where p.lastName = :lastName")
   fun getByLastName(lastName: String): List&lt;Person>
}</pre>



<p>When you call one of these methods, Spring Data JPA uses Jakarta Persistence’s EntityManager to instantiate a Query, set the provided bind parameters, execute the query, and map the result to a managed Person entity object.</p>



<pre class="EnlighterJSRAW" data-enlighter-language="generic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">2025-11-16T16:47:20.949+01:00 DEBUG 16193 --- [SDJWithKotlin] [           main] 
org.hibernate.SQL                        : select 
p1_0.id,p1_0.company_id,p1_0.first_name,p1_0.last_name,p1_0.version from person p1_0 
where p1_0.last_name=?
2025-11-16T16:47:20.952+01:00 TRACE 16193 --- [SDJWithKotlin] [           main]
org.hibernate.orm.jdbc.bind              : binding parameter (1:VARCHAR) &lt;- [Doe]
</pre>



<p>But entities are not the only projection you can use. For many use cases, a read-only DTO projection that only fetches the required information is more efficient. And Kotlin’s <a href="https://kotlinlang.org/docs/data-classes.html" target="_blank" rel="noopener">data classes</a> are a great way to model such a DTO.</p>



<p>If you only want to show the first and last names of multiple people along with the company they work for, you could use the following <code>PersonWithCompany</code> data class.</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">data class PersonWithCompany(
    val firstName: String,
    val lastName: String,
    val company: String
)</pre>



<p>In the next step, you can define a repository method that returns a <code>List</code> of those objects. If you annotate that method with a <code>@Query</code> annotation and provide a JPQL query that returns 3 fields with matching names, Spring Data JPA automatically maps each record to a <code>PersonWithCompany</code> object.</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">interface PersonRepository : JpaRepository&lt;Person, Long> {
   @Query("select p.firstName, p.lastName, c.name as company from Person p join p.company c")
   fun findPersonsWithCompany(): List&lt;PersonWithCompany>
}</pre>



<p>As you can see in the log output, using a data class as your query projection combines the convenience of Kotlin data classes in your business code with the performance benefits of fetching only the required information from the database.</p>



<pre class="EnlighterJSRAW" data-enlighter-language="generic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">2025-11-16T16:59:42.260+01:00 DEBUG 22541 --- [SDJWithKotlin] [           main]
org.hibernate.SQL                        : select p1_0.first_name,p1_0.last_name,c1_0.name from 
person p1_0 join company c1_0 on c1_0.id=p1_0.company_id
2025-11-16T16:59:42.278+01:00  INFO 22541 --- [SDJWithKotlin] [           main] c.t.j.k.s.SDJWithKotlinApplicationTests  : PersonWithCompany(firstName=Jane,
lastName=Doe, company=Mighty Business Corp)</pre>



<h2 class="wp-block-heading"><strong>Provide your own repository method implementations</strong></h2>



<p>If you need more flexibility than Spring Data JPA’s <code>@Query</code> annotation provides, you can also add your own method implementations to a repository. You do that by creating an interface that defines only the methods you want to implement, letting your repository extend that interface, and providing an implementation of that interface. This is called a fragment repository.</p>



<p>In this example, the <code>PersonFragmentRepository</code> defines the searchPerson method that expects a <code>PersonSearchInput</code> parameter.</p>



<pre class="EnlighterJSRAW" data-enlighter-language="generic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">interface PersonFragmentRepository {
   fun searchPerson(searchBy : PersonSearchInput): List&lt;Person?>?
}

data class PersonSearchInput(
   val firstName : String?,
   val lastName : String?,
   val worksForCompany : String?
) {}</pre>



<p>In the next step, you have to implement the <code>PersonFragmentRepository</code>. The name of your class should be the interface name with the postfix <code>Impl</code>. Spring Data then automatically detects this class, wires it into your repository, and delegates all calls to the searchPerson method to your class.</p>



<p>The goal of the following searchPerson implementation is to check which fields of the PersonSearchInput object are set and consider only those fields in the query’s WHERE clause. This is a typical implementation for complex search dialogs, where users can choose which information to search for.</p>



<pre class="EnlighterJSRAW" data-enlighter-language="generic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">override fun searchPerson(searchBy: PersonSearchInput): List&lt;Person?>? {
    val cBuilder = em.criteriaBuilder
    val cQuery = cBuilder.createQuery(Person::class.java)
    val person = cQuery.from(Person::class.java)
    val wherePredicates = mutableListOf&lt;Predicate>()

    searchBy.firstName?.let {
        wherePredicates.add(cBuilder.equal(person.get&lt;String>("firstName"), searchBy.firstName))
    }
    searchBy.lastName?.let {
        wherePredicates.add(cBuilder.equal(person.get&lt;String>("lastName"), searchBy.lastName))
    }
    searchBy.worksForCompany?.let {
        val company = person.join&lt;Person, Company>("company")
        wherePredicates.add(cBuilder.equal(company.get&lt;String>("name"), searchBy.worksForCompany))
    }

    cQuery.where(*wherePredicates.toTypedArray())
    return em.createQuery(cQuery).resultList
}</pre>



<p><strong>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</strong></p>



<p>As you can see in the code snippet, the searchPerson method uses Jakarta Persistence’s Criteria API to define a query based on the fields set on the provided PersonSearchInput object.</p>



<p>It first gets a <code>CriteriaBuilder</code> and uses it to create a <code>CriteriaQuery</code> that returns <code>Person</code> objects. It then defines the <code>FROM</code> clause and creates a <code>List of Predicates</code>. For each field of the <code>PersonSearchInput</code> object that’s not null, an equal predicate gets added to the <code>wherePredicates List</code>.</p>



<p>Thanks to Kotlin’s concise syntax and null handling, defining those <code>Predicates</code> is straightforward. Only the handling of the company name requires a little attention. If that field is set, you have to add a join to the <code>Company</code> entity before you can define the equal predicate.</p>



<p>You can then use the <code>wherePredicates</code> <code>List</code> to define the <code>WHERE</code> clause, execute the query, and return the result.</p>



<p>After you define the <code>PersonFragmentRepository</code> and implement it, you can use it in your repository definition. Let’s add it to the <code>PersonRepository</code>, which you already know from previous examples. It now extends Spring Data JPA’s JpaRepository and the <code>PersonFragmentRepository</code>.</p>



<pre class="EnlighterJSRAW" data-enlighter-language="generic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">interface PersonRepository : JpaRepository&lt;Person, Long>, PersonFragmentRepository {
    fun findByLastName(lastName: String): List&lt;Person>

    @Query("select p from Person p where p.lastName = :lastName")
    fun getByLastName(lastName: String): List&lt;Person>

    @Query("select p.firstName, p.lastName, c.name as company from Person p join p.company c")
    fun findPersonsWithCompany(): List&lt;PersonWithCompany>
}</pre>



<p>When you use this <code>PersonRepository</code> in your business code, Spring Data JPA provides the implementations of all methods defined by the <code>JpaRepository</code>. It also generates the implementations of the 3 query methods. Only the calls to the <code>searchPerson</code> method get delegated to your <code>PersonFragmentRepositoryImpl</code> class.</p>



<h2 class="wp-block-heading"><strong>Summary&nbsp;</strong></h2>



<p>As you’ve seen in this article, Kotlin works well with Spring Data JPA. You can model your entities and define repositories in the same way you would in a Java application. Kotlin’s concise syntax often makes these parts of your code easier to read and maintain without changing any persistence behavior. If you follow the established <a href="https://blog.jetbrains.com/idea/2026/01/how-to-avoid-common-pitfalls-with-jpa-and-kotlin/">Jakarta Persistence best practices for Kotlin</a>, you get a smooth development experience and an efficient persistence layer.</p>



<p>To learn more about persistence with Kotlin, check out two other articles in this series:  </p>



<ul>
<li><a href="https://blog.jetbrains.com/idea/2026/01/how-to-avoid-common-pitfalls-with-jpa-and-kotlin/">How to Avoid Common Pitfalls with JPA and Kotlin</a></li>



<li><a href="https://blog.jetbrains.com/idea/2026/04/using-spring-data-jdbc-with-kotlin/" data-type="link" data-id="https://blog.jetbrains.com/idea/2026/04/using-spring-data-jdbc-with-kotlin/">Using Spring Data JDBC With Kotlin</a></li>
</ul>



<h2 class="wp-block-heading">About the author</h2>


    <div class="about-author ">
        <div class="about-author__box">
            <div class="row">
                                                            <div class="about-author__box-img">
                            <img style="width:100% !important; height:auto !important; max-width:100% !important;" decoding="async" src="https://blog.jetbrains.com/wp-content/uploads/2025/12/Thorben-Janssen-400x400-1.jpg" alt="" loading="lazy">
                        </div>
                                        <div class="about-author__box-text">
                                                    <h4>Thorben Janssen</h4>
                                                <div class="p-client_container">
<div class="p-ia4_client_container">
<div class="p-ia4_client p-ia4_client--sidebar-wide p-ia4_client--with-split-view-feature">
<div class="p-client_workspace_wrapper" role="tabpanel" aria-label="JetBrains">
<div class="p-client_workspace">
<div class="p-client_workspace__layout">
<div class="p-client_workspace__tabpanel" role="tabpanel" aria-label="DMs">
<div class="enabled-managed-focus-container" role="none">
<div>
<div class="p-view_contents p-view_contents--primary" tabindex="-1" role="dialog" aria-label="Conversation with Teodor Irkhin">
<div class="tabbed_channel__Abx5r">
<div class="tabbed_channel__Abx5r">
<div class="channel_tab_panel__zJ5Bt c-tabs__tab_panel c-tabs__tab_panel--active c-tabs__tab_panel--full_height" role="none" data-qa="tabs_content_container">
<div class="p-file_drag_drop__container">
<div class="p-workspace__primary_view_body">
<div class="p-message_pane p-message_pane--classic-nav p-message_pane--scrollbar-float-adjustment p-message_pane--with-bookmarks-bar" data-qa="message_pane">
<div>
<div id="message-list" role="presentation">
<div id="message-list" class="c-virtual_list c-virtual_list--scrollbar c-message_list c-scrollbar c-scrollbar--fade" role="presentation">
<div class="c-scrollbar__hider" role="presentation" data-qa="slack_kit_scrollbar">
<div class="c-scrollbar__child" role="presentation">
<div class="c-virtual_list__scroll_container" role="presentation" data-qa="slack_kit_list">
<div id="message-list_1766072525.327379" class="c-virtual_list__item" tabindex="0" role="listitem" aria-setsize="-1" data-qa="virtual-list-item" data-item-key="1766072525.327379">
<div class="c-message_kit__background c-message_kit__background--hovered p-message_pane_message__message c-message_kit__message" role="presentation" data-qa="message_container" data-qa-unprocessed="false" data-qa-placeholder="false" data-msg-ts="1766072525.327379" data-msg-channel-id="D072Y30UX54">
<div class="c-message_kit__hover c-message_kit__hover--hovered" role="document" aria-roledescription="message" data-qa-hover="true">
<div class="c-message_kit__actions c-message_kit__actions--above">
<div class="c-message_kit__gutter">
<div class="c-message_kit__gutter__right" role="presentation" data-qa="message_content">
<div class="c-message_kit__blocks c-message_kit__blocks--rich_text">
<div class="c-message__message_blocks c-message__message_blocks--rich_text" data-qa="message-text">
<div class="p-block_kit_renderer" data-qa="block-kit-renderer">
<div class="p-block_kit_renderer__block_wrapper p-block_kit_renderer__block_wrapper--first">
<div class="p-rich_text_block" dir="auto">
<p>Thorben Janssen is a consultant and trainer who helps teams build better persistence layers with JPA and Hibernate. An international speaker with more than 20 years of experience in JPA and Hibernate, Thorben is the author of the best-selling book <i data-stringify-type="italic">Hibernate Tips: More than 70 solutions to common Hibernate problems</i>.</p>
<p>He also writes on thorben-janssen.com about various persistence topics, and to help developers improve their skills, he founded the Persistence Hub.</p>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
                    </div>
                            </div>
        </div>
    </div>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>AI-Assisted Java Application Development with Agent Skills</title>
		<link>https://blog.jetbrains.com/idea/2026/03/ai-assisted-java-application-development-with-agent-skills/</link>
		
		<dc:creator><![CDATA[Siva Katamreddy]]></dc:creator>
		<pubDate>Thu, 26 Mar 2026 13:21:10 +0000</pubDate>
		<featuredImage>https://blog.jetbrains.com/wp-content/uploads/2026/03/IJ-social-BlogFeatured-1280x720-1-3.png</featuredImage>		<category><![CDATA[ai]]></category>
		<category><![CDATA[idea]]></category>
		<category><![CDATA[java]]></category>
		<category><![CDATA[jetbrains-ai]]></category>
		<category><![CDATA[ai-agents]]></category>
		<category><![CDATA[claude-agent]]></category>
		<category><![CDATA[junie]]></category>
		<category><![CDATA[spring-boot]]></category>
		<guid isPermaLink="false">https://blog.jetbrains.com/?post_type=idea&#038;p=692555</guid>

					<description><![CDATA[Agent-assisted development is quickly becoming a common mode of software development. New techniques are emerging to help LLMs generate code that matches your preferences and standards. One common approach is to create an AGENTS.md, CLAUDE.md, or GEMINI.md file with project details, build instructions, and coding guidelines. The AI agent loads this file into context on [&#8230;]]]></description>
										<content:encoded><![CDATA[
<p>Agent-assisted development is quickly becoming a common mode of software development. New techniques are emerging to help LLMs generate code that matches your preferences and standards.</p>



<p>One common approach is to create an <strong>AGENTS.md</strong>, <strong>CLAUDE.md</strong>, or <strong>GEMINI.md</strong> file with project details, build instructions, and coding guidelines. The AI agent loads this file into context on every request.</p>



<p>This has two drawbacks:</p>



<ul>
<li>It consumes tokens on every request, increasing cost.</li>



<li>Loading too much context into an LLM degrades its effectiveness.</li>
</ul>



<p><br><a href="https://agentskills.io/" target="_blank" rel="noopener">Agent Skills</a> is a new initiative that solves both problems by managing context progressively and extending AI agent capabilities on demand.</p>



<h2 class="wp-block-heading">What are Agent Skills?</h2>



<p>Agent Skills is an open standard introduced by Anthropic, to extend AI agent capabilities with specialized knowledge and workflows.</p>



<p>Consider a use case where you want an AI to generate presentations using your company&#8217;s slide template and design guidelines. You can package those assets (the PPT template, font files, and design rules) into a <em>skill</em>. The agent then uses that skill to generate slides that match your standards automatically.</p>



<p>A skill is a folder containing a <strong>SKILL.md</strong> file. This file includes metadata (<code>name</code> and <code>description</code> at minimum) and instructions that tell an agent how to perform a specific task. Skills can also bundle scripts, templates, and reference materials.</p>



<pre class="EnlighterJSRAW" data-enlighter-language="generic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">skill-name/
├── SKILL.md          # Required: instructions + metadata
├── scripts/          # Optional: executable code
├── references/       # Optional: documentation
└── assets/           # Optional: templates, resources</pre>



<p>The format of a <strong>SKILL.md</strong> file is:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="generic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">---
name: name-of-the-skill
description: Skill description.
license: Apache-2.0
metadata:
  author: author/org
  version: "1.0"
compatibility: Requires git, docker, jq, and access to the internet
---

Skill Content</pre>



<p>In a <code>SKILL.md</code> file, <code>name</code> and <code>description</code> are required fields, and you can add optional fields like <code>licence</code>, <code>metadata</code>, <code>compatibility</code>, etc. You can explore more about the Skill Specification <a href="https://agentskills.io/specification" target="_blank" rel="noopener">here</a>.</p>



<h2 class="wp-block-heading">How do Agent Skills manage context?</h2>



<p>At startup, agents load only the metadata (name and description) of installed skills. When you ask the agent to perform a task, it finds the relevant skill and loads only that <strong>SKILL.md</strong> into context.</p>



<p>This progressive loading keeps context minimal and pulls in additional information only when needed, unlike a monolithic <strong>CLAUDE.md</strong> that loads everything upfront.</p>



<h2 class="wp-block-heading">What can be a skill?</h2>



<p>Skills extend AI capabilities across a wide range: from coding guidelines for a specific library, to step-by-step workflows with reference documents and helper scripts.</p>



<p>For example, you can create a skill that:</p>



<ul>
<li>Specifies which library APIs to use and which anti-patterns to avoid.</li>



<li>Bundles reference documentation in a <code>references/</code> directory.</li>



<li>Includes helper scripts in a <code>scripts/</code> directory.</li>
</ul>



<h2 class="wp-block-heading">Case Study: Implementing Spring Data JPA Pagination</h2>



<p>Suppose you ask an AI agent to implement a Spring Boot REST API endpoint that returns a paginated list of <code>Post</code> entities along with their <code>Comment</code> collections.</p>



<p>Without guidance, the agent is likely to produce one of these common mistakes:</p>



<ul>
<li><strong>N+1 SELECT problem</strong> — lazy-loading comments trigger a separate query per post.</li>



<li><strong>In-memory pagination</strong> — using <code>JOIN FETCH</code> with pagination loads all rows into memory, then paginates in the application layer.</li>
</ul>



<p><br>You can check out the sample code from the GitHub repository <a href="https://github.com/sivaprasadreddy/agent-skills-demo" target="_blank" rel="noopener">https://github.com/sivaprasadreddy/agent-skills-demo</a>&nbsp;</p>



<p>Let us see how an AI Agent might generate code when asked to implement a REST API endpoint to return paginated posts along with comments.</p>



<figure class="wp-block-video"><video controls src="https://blog.jetbrains.com/wp-content/uploads/2026/03/AIA-Junie-without-Skills.webm"></video></figure>



<p>Without any specific guidelines or skills, the AI Agent generated the following implementation:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="java" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">@RestController
@RequestMapping("/api/posts")
class PostController {
   private final PostService postService;

   PostController(PostService postService) {
       this.postService = postService;
   }

   @GetMapping
   PagedResult&lt;PostDto> getPosts(
           @RequestParam(name = "page", defaultValue = "1") int pageNo,
           @RequestParam(name = "size", defaultValue = "10") int pageSize) {
       return postService.getPosts(pageNo, pageSize);
   }

}


@Service
@Transactional(readOnly = true)
public class PostService {
   private final PostRepository postRepository;

   public PostService(PostRepository postRepository) {
       this.postRepository = postRepository;
   }

   public PagedResult&lt;PostDto> getPosts(int pageNo, int pageSize) {
       Sort sort = Sort.by(Sort.Direction.ASC, "id");
       Pageable pageable = PageRequest.of(pageNo &lt;= 0 ? 0 : pageNo - 1, pageSize, sort);
       Page&lt;PostDto> postPage = postRepository.findAllWithComments(pageable).map(PostDto::from);
       return PagedResult.from(postPage);
   }

}</pre>



<p>If you run the application and invoke the <code>GET /api/posts</code> endpoint, you will get the results, but in the logs you will find the below <strong>WARNING</strong>:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="generic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">HHH000104: firstResult/maxResults specified with collection fetch; applying in memory</pre>



<p>This essentially means, Hibernate will load all the entities into memory and then apply pagination. This will result in poor performance and even OutOfMemory exceptions if there are a large number of rows in the <code>posts</code> table.</p>



<p>A Spring Data JPA skill prevents both issues by giving the agent explicit guidelines and a working code example.</p>



<h2 class="wp-block-heading">Spring Data JPA Agent Skill</h2>



<p>Create a <code>spring-data-jpa/SKILL.md</code> file with the following content:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="generic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">---
name: spring-data-jpa-skill
description: Implement the persistence layer using Spring Data JPA in Spring Boot applications.
---

Follow the below principles when using Spring Data JPA:

1. Disable the Open Session in View (OSIV) filter: 
spring.jpa.open-in-view=false
2. Disable in-memory pagination: 
spring.jpa.properties.hibernate.query.fail_on_pagination_over_collection_fetch=true

3. Avoid the N+1 SELECT problem: use JOIN FETCH to load associated child collections in a single query.
4. Avoid in-memory pagination: when loading a paginated list of parent entities with child collections:
	* First, load only the parent IDs using pagination
	* Then, load the full entities with their child collections using JOIN FETCH for those IDs
	* Assemble the final Page from the paginated IDs and the loaded entities


## Pagination with child collections example:

PostRepository.java

public interface PostRepository extends JpaRepository&lt;Post, Long> {

   @Query("select p.id from Post p order by p.id")
   Page&lt;Long> findPostIds(Pageable pageable);

   @Query("select distinct p from Post p left join fetch p.comments where p.id in :ids")
   List&lt;Post> findAllByIdInWithComments(@Param("ids") Collection&lt;Long> ids);
}


PostService.java

@Service
public class PostService {
   private final PostRepository postRepository;

   public PostService(PostRepository postRepository) {
       this.postRepository = postRepository;
   }

   @Transactional(readOnly = true)
   public Page&lt;Post> findPosts(Pageable pageable) {
       Page&lt;Long> idsPage = postRepository.findPostIds(pageable);
       if (idsPage.isEmpty()) {
           return Page.empty(pageable);
       }
       List&lt;Post> posts = postRepository.findAllByIdInWithComments(idsPage.getContent());
       return new PageImpl&lt;>(posts, pageable, idsPage.getTotalElements());
   }
}</pre>



<h2 class="wp-block-heading">How to use Agent Skills?</h2>



<p>Agent Skills work with Claude Code, Codex, Gemini CLI, JetBrains Junie, and other agents. Install a skill at the project level or user level depending on your preference.</p>



<figure class="wp-block-table"><table><tbody><tr><td>Agent</td><td>Project-Level</td><td>User-Level</td></tr><tr><td>Junie</td><td><code>.junie/skills/</code></td><td><code>~/.junie/skills/</code></td></tr><tr><td>Claude Code</td><td><code>.claude/skills/</code></td><td><code>~/.claude/skills/</code></td></tr><tr><td>Codex</td><td><code>.agents/skills/</code></td><td><code>~/.agents/skills/</code></td></tr><tr><td>Gemini CLI</td><td><code>.gemini/skills/</code>(or)<code>.agents/skills/</code></td><td><code>~/.gemini/skills/</code>(or)<code>~/.agents/skills/</code></td></tr></tbody></table><figcaption class="wp-element-caption"><br></figcaption></figure>



<p>To use the Spring Data JPA skill with Claude Code:</p>



<ol>
<li>Copy the <code>spring-data-jpa/</code> directory into <code>{project-root}/.claude/skills/</code>.</li>



<li>Ask Claude Code to implement a paginated REST API endpoint.</li>



<li>Claude Code discovers the skill automatically and follows the guidelines.</li>
</ol>



<figure class="wp-block-video"><video controls src="https://blog.jetbrains.com/wp-content/uploads/2026/03/Agent-Skills-with-Claude-demo.webm"></video></figure>



<p>As you can see, Claude Code automatically discovered the Spring Data JPA skill and generated the following implementation following the guidelines given in the skill.</p>



<pre class="EnlighterJSRAW" data-enlighter-language="java" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">@Service
public class PostService {
   private final PostRepository postRepository;

   public PostService(PostRepository postRepository) {
       this.postRepository = postRepository;
   }

   @Transactional(readOnly = true)
   public Page&lt;Post> findPosts(Pageable pageable) {
       Page&lt;Long> idPage = postRepository.findPostIds(pageable);
       if (idPage.isEmpty()) {
           return Page.empty(pageable);
       }
       List&lt;Post> posts = postRepository.findAllByIdInWithComments(idPage.getContent());
       return new PageImpl&lt;>(posts, pageable, idPage.getTotalElements());
   }
}</pre>



<p>With this implementation, only the Post IDs of the desired page will be loaded first, and then a list of posts along with their comments will be fetched in a separate query. This will fix the pagination in-memory issue.</p>



<h2 class="wp-block-heading">Using Agent Skills with Junie</h2>



<p>You can use the <a href="https://junie.jetbrains.com/" data-type="link" data-id="https://junie.jetbrains.com/" target="_blank" rel="noopener">JetBrains Junie</a> Agent to generate code which automatically loads the necessary skills from <code>.junie/skills</code>&nbsp; and directory.</p>



<figure class="wp-block-video"><video controls src="https://blog.jetbrains.com/wp-content/uploads/2026/03/AIA-Junie-Skills.webm"></video></figure>



<p>The Junie agent loaded <code>spring-data-jpa</code> skill based on the given task and applied the guidelines. You can also observe that Junie automatically runs the relevant tests to verify the generated code is working or not and iterate until the tests are passed.</p>



<p>In the sample repository <a href="https://github.com/sivaprasadreddy/agent-skills-demo" target="_blank" rel="noopener">https://github.com/sivaprasadreddy/agent-skills-demo</a>, you can find the following branches to try out the spring-data-jpa Agent Skill:</p>



<ul>
<li><code>main</code>: Starting point to try implementing the mentioned usecase without any skills.</li>



<li><code>in-memory-pagination-issue</code>: Usecase implementation generated by AI that results in in-memory pagination issue.</li>



<li><code>skills</code>: With <code>spring-data-jpa</code> skill to try implementing the mentioned usecase.</li>
</ul>



<h2 class="wp-block-heading">Summary</h2>



<p>If the AI agent is generating code with any anti-patterns or not following team coding standards and conventions, instead of fixing issues one-by-one with follow-up prompts, consider creating a skill to provide those as guidelines.</p>



<p>To explore more on Agent Skills, please refer to the following resources:</p>



<ul>
<li><a href="https://agentskills.io/" target="_blank" rel="noopener">https://agentskills.io/</a></li>



<li><a href="https://platform.claude.com/docs/en/agents-and-tools/agent-skills/overview" target="_blank" rel="noopener">https://platform.claude.com/docs/en/agents-and-tools/agent-skills/overview</a></li>



<li><a href="https://developers.openai.com/codex/skills/" target="_blank" rel="noopener">https://developers.openai.com/codex/skills/</a></li>



<li><a href="https://geminicli.com/docs/cli/skills/" target="_blank" rel="noopener">https://geminicli.com/docs/cli/skills/</a></li>



<li><a href="https://junie.jetbrains.com/docs/agent-skills.html" target="_blank" rel="noopener">https://junie.jetbrains.com/docs/agent-skills.html</a>&nbsp;</li>
</ul>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>IntelliJ IDEA 2026.1 Is Out!</title>
		<link>https://blog.jetbrains.com/idea/2026/03/intellij-idea-2026-1/</link>
		
		<dc:creator><![CDATA[Maria Kosukhina]]></dc:creator>
		<pubDate>Wed, 25 Mar 2026 14:28:29 +0000</pubDate>
		<featuredImage>https://blog.jetbrains.com/wp-content/uploads/2026/03/IJ-IDEA-2026.1-BlogFeatured.png</featuredImage>		<category><![CDATA[releases]]></category>
		<guid isPermaLink="false">https://blog.jetbrains.com/?post_type=idea&#038;p=692136</guid>

					<description><![CDATA[IntelliJ IDEA 2026.1 is here, and it comes packed with an array of new features and enhancements to elevate your coding experience!&#160; You can download this latest release from our&#160;website&#160;or update to it directly from inside the IDE, via the free&#160;Toolbox App, or using snap packages for Ubuntu. As always, all new features are brought [&#8230;]]]></description>
										<content:encoded><![CDATA[
<p>IntelliJ IDEA 2026.1 is here, and it comes packed with an array of new features and enhancements to elevate your coding experience!&nbsp;</p>



<p>You can download this latest release from our&nbsp;<a href="https://www.jetbrains.com/idea/download/" target="_blank" rel="noreferrer noopener">website</a>&nbsp;or update to it directly from inside the IDE, via the free&nbsp;<a href="https://www.jetbrains.com/toolbox-app/" target="_blank" rel="noreferrer noopener">Toolbox App</a>, or using snap packages for Ubuntu.</p>



<p>As always, all new features are brought together on the <a href="https://www.jetbrains.com/idea/whatsnew/" data-type="link" data-id="https://www.jetbrains.com/idea/whatsnew/" target="_blank" rel="noopener">What’s New page</a>, with detailed explanations and demos.</p>



<p align="center"><a class="jb-download-button" href="https://www.jetbrains.com/idea/whatsnew/" target="_blank" rel="noopener">Explore the What&#8217;s New page</a></p>



<p>In addition to the What’s New page, our developer advocates got together to discuss and demonstrate the key updates. If you prefer watching to reading, check it out.</p>



<figure class="wp-block-embed is-type-video is-provider-youtube wp-block-embed-youtube wp-embed-aspect-16-9 wp-has-aspect-ratio"><div class="wp-block-embed__wrapper">
<iframe loading="lazy" title="What&#039;s New In IntelliJ IDEA 2026.1" src="https://www.youtube.com/embed/FVsMsCFtlOs?feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe>
</div></figure>



<p>IntelliJ IDEA 2026.1 brings built-in support for more AI agents, including Codex, Cursor, and any ACP-compatible agent, and delivers targeted, first-class improvements for Java, Kotlin, and Spring. The release also advances IntelliJ IDEA’s mission to provide support for the latest languages and tools from day one.</p>



<p><em>Please note that some AI features may work differently or be unavailable in your region. <a href="https://www.jetbrains.com.cn/ai-china/" target="_blank" rel="noreferrer noopener">Learn more</a>.</em></p>



<p><strong>Any agent, built-in:</strong></p>



<ul>
<li>ACP Registry: Browse and install AI agents in one click.</li>



<li>Git worktrees: Work in parallel branches and hand one off to an agent while you keep moving in another.</li>



<li>Database access for AI agents: Let Codex or Claude Agent query and modify your data sources natively.</li>
</ul>



<p></p>



<p><strong>Intelligence in the platform:</strong></p>



<ul>
<li>Quota-free next edit suggestions: Propagate changes throughout a given file with IDE-driven assistance.</li>



<li>Spring runtime insight: Inspect injected beans, endpoint security, and property values without pausing execution.</li>



<li>Kotlin-aware JPA: Detect and fix Kotlin-specific pitfalls in Jakarta Persistence entities.</li>
</ul>



<p></p>



<p><strong>First-class language support:</strong></p>



<ul>
<li>Java 26: Enjoy day-one support, including preview features.</li>



<li>Kotlin 2.3.20: Enjoy day-one support, including experimental features.</li>



<li>C/C++ in IntelliJ IDEA: Access first-class C/C++ coding assistance for multi-language projects.</li>



<li>Support for JavaScript without an Ultimate subscription.</li>
</ul>



<p></p>



<p><strong>Productivity and environment:</strong></p>



<ul>
<li>Expanded command completion, now with AI actions, postfix templates, and config file support.</li>



<li>Better performance for large-scale TypeScript projects.</li>



<li>Native Dev Container workflow: Open containerized projects as if they were local.</li>
</ul>



<p></p>



<p>Along with new features, 2026.1 delivers numerous stability, performance, and usability improvements across the platform. These are described in a separate <a href="https://blog.jetbrains.com/idea/2026/03/whats-fixed-intellij-idea-2026-1/">What’s Fixed blog post</a>.</p>



<p>As always, your feedback plays an important role in shaping IntelliJ IDEA. Tell us what you think about the new features and help guide future improvements.</p>



<p>Join the discussion on <a href="https://x.com/intellijidea" target="_blank">X</a>, <a href="https://www.linkedin.com/showcase/intellijidea/" target="_blank" rel="noopener">LinkedIn</a>, or <a href="https://bsky.app/profile/intellijidea.com" target="_blank" rel="noopener">Bluesky</a>, and if you encounter any issues, please report them via <a href="https://youtrack.jetbrains.com/issues/IDEA" target="_blank" rel="noopener">YouTrack</a>.</p>



<p>For full details of the improvements introduced in version 2026.1, refer to the <a href="https://youtrack.jetbrains.com/articles/IDEA-A-2100662652/IntelliJ-IDEA-2026.1-261.22158.277-build-Release-Notes" data-type="link" data-id="https://youtrack.jetbrains.com/articles/IDEA-A-2100662652/IntelliJ-IDEA-2026.1-261.22158.277-build-Release-Notes" target="_blank" rel="noopener">release notes</a>.</p>



<p>Thank you for using IntelliJ IDEA. Happy developing!</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>What’s fixed in IntelliJ IDEA 2026.1</title>
		<link>https://blog.jetbrains.com/idea/2026/03/whats-fixed-intellij-idea-2026-1/</link>
		
		<dc:creator><![CDATA[Dmitriy Smirnov]]></dc:creator>
		<pubDate>Wed, 25 Mar 2026 10:48:22 +0000</pubDate>
		<featuredImage>https://blog.jetbrains.com/wp-content/uploads/2026/03/IJ-IDEA-2026.1-whats-fixed.png</featuredImage>		<category><![CDATA[releases]]></category>
		<guid isPermaLink="false">https://blog.jetbrains.com/?post_type=idea&#038;p=691936</guid>

					<description><![CDATA[Welcome to the overview of fixes and improvements in IntelliJ IDEA 2026.1. In this release, we have resolved over 1,000 bugs and usability issues, including 334 reported by users. Below are the most impactful changes that will help you work with greater confidence every day. Performance We continue to prioritize reliability, working to improve application [&#8230;]]]></description>
										<content:encoded><![CDATA[<p>Welcome to the overview of fixes and improvements in IntelliJ IDEA 2026.1.</p>
<p>In this release, we have resolved <a href="https://youtrack.jetbrains.com/issues?q=Project:%20IDEA,%20IJPL,%20WEB%20Available%20in:%202026.1*%20%23resolved%20sort%20by:%20votes%20visible%20to:%20%7Bissue%20readers%7D%20Type:%20Bug,%20%7BUsability%20Problem%7D" target="_blank" rel="noopener">over 1,000 bugs and usability issues</a>, including <a href="https://youtrack.jetbrains.com/issues?q=Project:%20IDEA,%20IJPL,%20WEB%20Available%20in:%202026.1*%20%23resolved%20sort%20by:%20votes%20visible%20to:%20%7Bissue%20readers%7D%20Type:%20Bug,%20%7BUsability%20Problem%7D%20reporter:%20-jetbrains-team" target="_blank" rel="noopener">334<br />
reported by users</a>. Below are the most impactful changes that will help you work with greater confidence every day.</p>
<h2 id="performance">Performance</h2>
<p>We continue to prioritize reliability, working to improve application performance, fix freezes, optimize operations, and cover the most common use cases with metrics. Using our internal tools, we identified and resolved 40 specific scenarios that caused UI freezes.</p>
<p>However, internal tooling alone cannot uncover every issue. To identify additional cases, we enabled automatic error and freeze reporting in EAP builds. By collecting this data, we gain a real, unfiltered picture of what’s going wrong, how often it happens, and how many users are affected. This allows us to prioritize fixes based on real impact rather than guesswork.</p>
<p>As always, we prioritize your privacy and security. When using EAP builds, you maintain full control and can disable automatic error and freeze reporting in <em>Settings</em> | <em>Appearance &amp; Behavior</em> | <em>System Settings</em> | <em>Data Sharing</em>. Thank you for helping us build better tools!</p>
<h2 id="terminal">Terminal</h2>
<p>Version 2026.1 enhances your productivity by streamlining the experience offered by the terminal, a crucial workspace for developer workflows involving CLI-based AI agents.</p>
<p>First, we fixed the <a href="https://youtrack.jetbrains.com/issue/IJPL-184110" target="_blank" rel="noopener"><em>Esc</em> behavior</a> – it is now handled by the shell instead of switching focus to the editor, so it does not break the AI-agent workflow. Additionally, <a href="https://youtrack.jetbrains.com/issue/IJPL-221848" target="_blank" rel="noopener"><em>Shift</em>+<em>Enter</em> now inserts a new line</a>, making it easier to write multi-line prompts and commands directly. This behavior can be disabled in <em>Settings</em> | <em>Advanced Settings</em> | <em>Terminal</em>.</p>
<p>We also improved the detection of <a href="https://youtrack.jetbrains.com/issue/IJPL-206783" target="_blank" rel="noopener">absolute</a> and <a href="https://youtrack.jetbrains.com/issue/IJPL-232564" target="_blank" rel="noopener">relative</a> file paths in terminal output, allowing you to open files and folders with a single click in any context. When you encounter compilation or build errors, or submit a task to an AI coding agent, you can jump directly to the referenced file and review or fix issues faster.</p>
<p>Link navigation is activated by <a href="https://youtrack.jetbrains.com/issue/IJPL-221853" target="_blank" rel="noopener">holding <em>Ctrl</em></a> (or <em>Cmd</em> on macOS) and clicking – just like in external terminals.</p>
<h2 id="jvm-language-support">JVM language support</h2>
<h3 id="better-kotlin-bean-registration-support">Better Kotlin bean registration support</h3>
<p>Kotlin’s strong DSL capabilities are a perfect fit for Spring Framework 7’s BeanRegistrar API. In 2026.1, we’ve made working with programmatic registration as productive as annotation-based configuration.</p>
<p>The IDE ensures complete visibility into your application structure thanks to the <em>Structure</em> tool window, providing better endpoint visibility, intuitive navigation with gutter icons, integrated HTTP request generation, and path variable support.</p>
<h3 id="new-kotlin-coroutine-inspections">New Kotlin coroutine inspections</h3>
<p>To help maintain code quality, we’ve introduced a set of new inspections for the Kotlin coroutines library, covering common pitfalls.</p>
<p>Read more about coroutine inspections in <a href="https://blog.jetbrains.com/idea/2026/03/intellij-idea-s-new-kotlin-coroutine-inspections-explained/">this article</a>.</p>
<h3 id="scala">Scala</h3>
<p>Working with sbt projects inside WSL and Docker containers is now as smooth as working with local projects. We’ve also improved code highlighting performance and sped up sbt project synchronization.</p>
<p>To reduce cognitive load and provide a more ergonomic UI, we’ve redesigned the Scala code highlighting settings. A new <em>Settings</em> page consolidates previously scattered options, making them cleaner, more intuitive, and easier to access.</p>
<p>You can now disable built-in inspections when compiler highlighting is sufficient, or configure compilation delay for compiler-based highlighting. Settings for Scala 2 and Scala 3 projects are now independent, and the type-aware highlighting option has been integrated with the rest of the settings.</p>
<p>You can read more about these updates <a href="https://blog.jetbrains.com/scala/2026/03/23/intellij-scala-plugin-2026-1-is-out">this article</a>.</p>
<h2 id="spring">Spring</h2>
<p>Spring support remains a core focus for IntelliJ IDEA. We are committed to maximizing reliability and reducing friction in your daily development.</p>
<p>In this release, we made a dedicated effort to address <a href="https://youtrack.jetbrains.com/issue/IDEA-370094/Spring-Boot-Run-Problems-2026.1" target="_blank" rel="noopener">issues related to running Spring Boot application</a> from the IDE. There are now even fewer reasons to run your application in the terminal &#8211; just run it in the IDE and use the debugger when you need deeper insights.</p>
<h3 id="API-versioning">Spring Boot 4 API versioning support</h3>
<p>This is a new Spring Boot feature, and we keep improving its support based on your feedback. In this version, we added .yml files support for version configuration, fixed false positives and added a couple of useful inspections, so you get an instant feedback about issues without running the app.</p>
<h3 id="API-versioning">Flyway DB Migrations</h3>
<p>To ensure a reliable and distraction-free experience, the IDE now verifies migration scripts only when a data source is active, eliminating false-positive errors when the data source is disconnected.</p>
<p>At the same time, Flyway scripts got correct navigation to the table definitions, and SQL autocompletion for any files and tables defined in them.</p>
<h2 id="user-interface">User interface</h2>
<p>With IntelliJ IDEA 2026.1, we’ve continued to prioritize ultimate comfort and an ergonomic UI, ensuring your workspace is as accessible and customizable as your code.</p>
<p>The long-awaited ability to <a href="https://youtrack.jetbrains.com/issue/IJPL-54591" target="_blank" rel="noopener">sync the IDE theme with the OS</a> is now available to Linux users, bringing parity with macOS and Windows. Enable it in <em>Settings</em> |<em>Appearance &amp; Behavior</em> | <em>Appearance</em>.</p>
<p>The code editor now supports <a href="https://youtrack.jetbrains.com/issue/IJPL-26382" target="_blank" rel="noopener">OpenType stylistic sets</a>. Enjoy more expressive typography with your favorite fonts while coding. Configure them via <em>Editor</em> |<em>Font</em>, and preview glyph changes instantly with a helpful tooltip before applying a set.</p>
<p>Windows users who rely on the keyboard can now bring the IDE’s main menu into focus by <a href="https://youtrack.jetbrains.com/issue/IJPL-58454" target="_blank" rel="noopener">pressing the <em>Alt</em> key</a>. This change improves accessibility for screen reader users.</p>
<h2 id="version-control">Version control</h2>
<p>We continue to make small but impactful improvements that reduce friction and support your everyday workflow.</p>
<p>You can now [coming in 2026.1.1 update] <a href="https://youtrack.jetbrains.com/issue/IJPL-219835" target="_blank" rel="noopener">amend any recent commit</a> directly from the <em>Commit</em> tool window – no more ceremonies involving interactive rebase. Simply select the target commit and the necessary changes, then confirm them – the IDE will take care of the rest.</p>
<p>In addition to Git worktrees, we’ve improved branch workflows by introducing the <a href="https://youtrack.jetbrains.com/issue/IJPL-73967" target="_blank" rel="noopener"><em>Checkout &amp; Update</em></a> action, which pulls all remote changes.</p>
<p>Furthermore, fetching changes can now be automated – no need for a separate plugin. Enable <em>Fetch remote changes automatically</em> in <em>Settings</em> | <em>Git</em>.</p>
<p>In-IDE reviews for GitLab merge requests now offer near feature parity with the web interface. <a href="https://youtrack.jetbrains.com/issue/IJPL-82603" target="_blank" rel="noopener">Multi-line comments</a>, <a href="https://youtrack.jetbrains.com/issue/IJPL-84177" target="_blank" rel="noopener">comment navigation</a>, <a href="https://youtrack.jetbrains.com/issue/IJPL-82619" target="_blank" rel="noopener">image uploads</a>, and <a href="https://youtrack.jetbrains.com/issue/IJPL-82596" target="_blank" rel="noopener">assignee selection</a> when creating a merge request are all available directly in the IDE, so you can stay focused without switching to the browser.</p>
<p>The Subversion, Mercurial, and Perforce plugins are no longer bundled with the IDE distribution, but you can still install them from <a href="https://plugins.jetbrains.com/" target="_blank" rel="noopener">JetBrains Marketplace</a>.</p>
<h2 id="databases">Databases</h2>
<p>We’ve enhanced the <em>Explain Plan</em> workflow with UI optimizations for the <em>Query Plan</em> tab, an additional separate pane for details about the execution plan row, inner tabs that hold flame graphs, and an action to copy the query plan in the database’s native format.</p>
<h2 id="jetbrains-daemon">JetBrains daemon</h2>
<p>IntelliJ IDEA 2026.1 includes a lightweight background service – <a href="https://www.jetbrains.com/help/toolbox-app/daemon.html" target="_blank" rel="noopener">jetbrainsd</a> – that handles jetbrains:// protocol links from documentation, learning resources, and external tools, opening them directly in your IDE without requiring you to have the Toolbox App running.</p>
<h2 id="sunsetting-of-code-with-me">Sunsetting of Code With Me</h2>
<p>As of version 2026.1, Code With Me will be unbundled from all JetBrains IDEs and will instead be available as a separate plugin on JetBrains Marketplace. Version 2026.1 will be the last IDE release to officially support Code With Me as we gradually sunset the service.</p>
<p>Read the full announcement and timeline in <a href="https://blog.jetbrains.com/platform/2026/03/sunsetting-code-with-me/">our blog post</a>.</p>
<h2 id="enhanced-ai-management-and-analytics-for-organizations">Enhanced AI management and analytics for organizations</h2>
<p>We are working hard to provide development teams with centralized control over AI and built-in analytics to understand adoption, usage, and cost. As part of the effort, we’ve <a href="https://blog.jetbrains.com/ai/2026/02/enhanced-ai-management-and-analytics-for-organizations/">introduced the JetBrains Console</a>. It adds visibility into how your teams use AI in practice, including information about active users, credit consumption, and acceptance rates for AI-generated code.</p>
<p>The JetBrains Console is available to all organizations with a JetBrains AI subscription, providing the trust and visibility required to manage professional-grade development at any scale.</p>
<p>That’s it for this overview.</p>
<p>Let us know what you think about the fixes and priorities in this release. Your feedback helps us steer the product so it works best for you!</p>
<p>We’d also love to hear your thoughts on this overview and the format in general.</p>
<p>Update to IntelliJ IDEA 2026.1 now and see how it has improved. Don’t forget to join us on <a href="https://x.com/IntelliJIDEA" target="_blank">X</a> , <a href="https://bsky.app/profile/intellijidea.com/" target="_blank" rel="noopener">Bluesky</a>, or <a href="https://www.linkedin.com/showcase/intellijidea" target="_blank" rel="noopener">LinkedIn</a> and share your favorite updates.</p>
<p>Thank you for using IntelliJ IDEA!</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Core JavaScript and TypeScript Features Become Free in IntelliJ IDEA</title>
		<link>https://blog.jetbrains.com/idea/2026/03/js-ts-free-support/</link>
		
		<dc:creator><![CDATA[Julia Shashkova]]></dc:creator>
		<pubDate>Thu, 19 Mar 2026 11:43:34 +0000</pubDate>
		<featuredImage>https://blog.jetbrains.com/wp-content/uploads/2026/03/IJ-social-BlogFeatured-js-ts-1.png</featuredImage>		<category><![CDATA[news]]></category>
		<guid isPermaLink="false">https://blog.jetbrains.com/?post_type=idea&#038;p=684420</guid>

					<description><![CDATA[Modern Java development often involves web technologies. To make this workflow more accessible and smoother, we’re making some core JavaScript, TypeScript, HTML, and CSS features – previously included with the Ultimate subscription only – available for free in IntelliJ IDEA v2026.1. JavaScript, TypeScript, HTML, CSS, and React Support Enjoy a comprehensive set of features for [&#8230;]]]></description>
										<content:encoded><![CDATA[
<p>Modern Java development often involves web technologies. To make this workflow more accessible and smoother, we’re making some core JavaScript, TypeScript, HTML, and CSS features – previously included with the Ultimate subscription only – available for free in IntelliJ IDEA v2026.1.</p>



<h2 class="wp-block-heading">JavaScript, TypeScript, HTML, CSS, and React Support</h2>



<p>Enjoy a comprehensive set of features for building modern web applications:</p>



<ul>
<li><strong>Basic React support</strong>, including code completion, component and attribute navigation, and React component and prop rename refactorings.</li>
</ul>



<ul>
<li><strong>Full syntax highlighting</strong> for JavaScript, TypeScript, HTML, and CSS, ensuring better readability and usability of frontend code inside the IDE.<br><img decoding="async" loading="lazy" class="wp-image-685026" style="width: 1500px;; width:100% !important; height:auto !important; max-width:100% !important;" src="https://blog.jetbrains.com/wp-content/uploads/2026/03/js-ts-syntax-2026-1.jpg" alt="Full syntax highlighting for JavaScript, TypeScript, HTML, and CSS"></li>



<li><strong>Reliable code completion</strong> to write code faster and with fewer errors across both backend and frontend parts of your web application.<img decoding="async" loading="lazy" class="wp-image-685065" style="width: 1500px;; width:100% !important; height:auto !important; max-width:100% !important;" src="https://blog.jetbrains.com/wp-content/uploads/2026/03/js-ts-completion-2026-1.png" alt="code completion for JS and TS"></li>
</ul>



<ul>
<li><strong>Advanced import management</strong> automatically handles JavaScript and TypeScript imports as you code, adds missing references when pasting code, and cleans up unused ones with <em>Optimize Imports</em> – helping you save time, reduce errors, and keep your codebase clean.</li>



<li><strong>Smooth code navigation </strong>via dedicated gutter icons for <em>Jump to&#8230;</em> actions, recursive calls, TypeScript source mapping, and more.<img decoding="async" loading="lazy" class="wp-image-685037" style="width: 1500px;; width:100% !important; height:auto !important; max-width:100% !important;" src="https://blog.jetbrains.com/wp-content/uploads/2026/03/js-ts-navigation-2026-1.png" alt="code navigation for JS and TS"></li>
</ul>



<h2 class="wp-block-heading">Code Intelligence and Code Quality</h2>



<p>Improve and maintain your web code with built-in intelligence and quality tools:</p>



<ul>
<li><strong>Core web refactorings:</strong> Make changes to your code with reliable <em>Rename</em> refactorings and actions (<em>Introduce Variable</em>, <em>Introduce Constant</em>, <em>Change Signature</em>, <em>Move Members</em>, and more).</li>



<li><strong>Quality control</strong>: Identify potential issues early with built-in inspections, intentions, and quick fixes, and get improvement suggestions as you code.</li>



<li><strong>Code cleanup</strong>: Keep your codebase clean with JavaScript and TypeScript duplicate detection, making it easier to spot and eliminate redundant code.</li>
</ul>



<h2 class="wp-block-heading">Integrated workflows</h2>



<p>Now it’s easier to manage, maintain, and secure your web projects from within a single environment.</p>



<ul>
<li><strong>Create</strong> <strong>new web projects </strong>quickly by using the built-in Vite generator.</li>



<li><strong>Keep your codebase consistent and clean</strong> with integrated support for Prettier, ESLint, TSLint, and StyleLint.</li>



<li><strong>Execute NPM scripts </strong>directly from <code>package.json</code>.<br><img decoding="async" loading="lazy" class="wp-image-685048" style="width: 1500px;; width:100% !important; height:auto !important; max-width:100% !important;" src="https://blog.jetbrains.com/wp-content/uploads/2026/03/js-ts-npm-script-2026-1.png" alt="Execute NPM scripts directly from package.json"></li>



<li><strong>Monitor your project dependencies</strong> and identify known security vulnerabilities early.</li>
</ul>



<p>Enjoy building your web applications with IntelliJ IDEA, and happy developing!</p>



<p><em>If you need more advanced tools (dedicated debugger, test runners, test UI tooling, support for all frontend frameworks including Angular, Vue, advanced refactorings, and more) for full-stack application development, you can try them with the Ultimate subscription trial. The trial provides 30 days of full access – no credit card required.</em></p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>IntelliJ IDEA&#8217;s New Kotlin Coroutine Inspections, Explained</title>
		<link>https://blog.jetbrains.com/idea/2026/03/intellij-idea-s-new-kotlin-coroutine-inspections-explained/</link>
		
		<dc:creator><![CDATA[Irina Mariasova]]></dc:creator>
		<pubDate>Thu, 19 Mar 2026 10:00:58 +0000</pubDate>
		<featuredImage>https://blog.jetbrains.com/wp-content/uploads/2026/03/IJ-social-BlogFeatured-1280x720-1-1.png</featuredImage>		<category><![CDATA[kotlin]]></category>
		<category><![CDATA[coroutines]]></category>
		<category><![CDATA[inspections]]></category>
		<guid isPermaLink="false">https://blog.jetbrains.com/?post_type=idea&#038;p=689112</guid>

					<description><![CDATA[This article was written by an external contributor. Every technology has its misuses, and different ecosystems use different approaches to prevent them. In the Kotlin ecosystem, I believe the philosophy has always been to make APIs so good that correct usage is simple and intuitive, while misuse is harder and more complicated. This differs from [&#8230;]]]></description>
										<content:encoded><![CDATA[
<p><em>This article was written by an external contributor.</em></p>


    <div class="about-author ">
        <div class="about-author__box">
            <div class="row">
                                                            <div class="about-author__box-img">
                            <img style="width:100% !important; height:auto !important; max-width:100% !important;" decoding="async" src="https://blog.jetbrains.com/wp-content/uploads/2025/10/image-96.png" alt="" loading="lazy">
                        </div>
                                        <div class="about-author__box-text">
                                                    <h4>Marcin Moskała</h4>
                                                <p>Marcin is a highly experienced developer and Kotlin instructor, founder of Kt. Academy, an official JetBrains partner specializing in Kotlin training. He is also a Google Developers Expert and a well-known contributor to the Kotlin community. Marcin is the author of several widely recognized books, including <em data-start="450" data-end="468">Effective Kotlin</em>, <em data-start="470" data-end="489" data-is-only-node="">Kotlin Coroutines</em>, <em data-start="491" data-end="510">Functional Kotlin</em>, <em data-start="512" data-end="529">Advanced Kotlin</em>, <em data-start="531" data-end="550">Kotlin Essentials</em>, and <em data-start="556" data-end="589">Android Development with Kotlin</em>.</p>
<p><a href="https://kt.academy/" target="_blank" rel="noopener">Website</a></p>
                    </div>
                            </div>
        </div>
    </div>



<p>Every technology has its misuses, and different ecosystems use different approaches to prevent them. In the Kotlin ecosystem, I believe the philosophy has always been to make APIs so good that correct usage is simple and intuitive, while misuse is harder and more complicated. This differs from JavaScript, which has plenty of legacy practices (like using == instead of ===, or <code>var</code> instead of <code>let/const</code>) and relies more on warnings. However, not everything can be enforced by good design, and Kotlin also uses warnings to guide developers in writing better code.&nbsp;</p>



<p>Today, IntelliJ IDEA introduces a set of new inspections for the Kotlin coroutines library. I’ve seen these issues in many codebases and addressed them through my books, articles, and workshops. These patterns often show up, so let’s walk through why they are problematic and how to handle them correctly.&nbsp;</p>



<p>Note: These inspections are also available in Android Studio. You can check how IntelliJ IDEA versions map to Android Studio versions <a href="https://plugins.jetbrains.com/docs/intellij/android-studio-releases-list.html#2025" target="_blank" rel="noopener">here</a>.&nbsp;</p>



<h2 class="wp-block-heading"><code>awaitAll()</code>and <code>joinAll()</code></h2>



<p>Available since IntelliJ IDEA 2025.2</p>



<figure class="wp-block-image size-full"><img style="width:100% !important; height:auto !important; max-width:100% !important;" decoding="async" loading="lazy" src="https://blog.jetbrains.com/wp-content/uploads/2026/03/image-34.png" alt="" class="wp-image-689987"/></figure>



<p>If you use map <code>{ it.await() }</code>, IntelliJ IDEA will suggest <code>awaitAll()</code>. If you use <code>forEach { it.join() }</code>, it will suggest <code>joinAll()</code>. Why? These alternatives are cleaner, and <code>awaitAll()</code> is also more efficient and better represents waiting for multiple tasks, as it waits for all elements concurrently rather than one after another.&nbsp;</p>



<p><code>awaitAll()</code> also behaves more efficiently in the presence of exceptions. Imagine awaiting 100 coroutines, and the fiftieth throws an exception. <code>awaitAll()</code> will immediately rethrow the exception, unlike map <code>{ it.await() }</code>, which would wait for the first 49 coroutines before throwing the exception. In most cases, this behavior cannot be observed because of other exception propagation mechanisms.&nbsp;</p>



<h2 class="wp-block-heading"><code>currentCoroutineContext()</code> over <code>coroutineContext</code></h2>



<p>Available since IntelliJ IDEA 2025.2</p>



<figure class="wp-block-image size-full"><img style="width:100% !important; height:auto !important; max-width:100% !important;" decoding="async" loading="lazy" src="https://blog.jetbrains.com/wp-content/uploads/2026/03/image_2.png" alt="" class="wp-image-689310"/></figure>



<p>All suspending functions can access the context of the coroutine in which they are called. Traditionally, this was done via the <code>coroutineContext</code> property. The problem is that <code>CoroutineScope</code>, which is implicitly available in coroutine starters, such as launch, <code>coroutineScope</code>, and <code>runTest</code>, has a property with the same name. This can be confusing and lead to issues. Consider the following example:&nbsp;</p>



<figure class="wp-block-image size-full"><img style="width:100% !important; height:auto !important; max-width:100% !important;" decoding="async" loading="lazy" src="https://blog.jetbrains.com/wp-content/uploads/2026/03/image12.png" alt="" class="wp-image-689321"/></figure>



<p>This code tests the <code>mapAsync</code> function and checks whether it correctly propagates context from the caller to the transformation. It is incorrect. Within the transformation, we could read the caller context from the <code>coroutineContext</code>, but not in this situation. This lambda is defined inside <code>runTest</code>, and the <code>coroutineContext</code> property from <code>CoroutineScope</code> (provided by <code>runTest</code>) takes priority over the top-level <code>coroutineContext</code> property. This kind of mistake is quite common, which is why the <code>currentCoroutineContext()</code> function was introduced to read the context of the coroutine that runs a suspending function. You should use it instead of <code>coroutineContext</code>.&nbsp;</p>



<h2 class="wp-block-heading"><code>runBlocking</code> inside a suspending function</h2>



<p>Available since IDEA 2025.2</p>



<p>Using <code>runBlocking</code> inside suspending functions is a serious issue. It blocks the calling thread, which defeats the purpose of coroutines.</p>



<figure class="wp-block-image size-full"><img style="width:100% !important; height:auto !important; max-width:100% !important;" decoding="async" loading="lazy" src="https://blog.jetbrains.com/wp-content/uploads/2026/03/image10-2.png" alt="" class="wp-image-689332"/></figure>



<p>So what can you use instead? That depends on what you want to achieve. In most cases, you don’t need it. If you need to create a coroutine scope, use <code>coroutineScope { … }</code>. If you need to change context, use <code>withContext(ctx) { … }</code>.<br>Watch out for situations where a suspending function calls a regular function that uses runBlocking. Opt for making this function suspend to avoid making a blocking call.&nbsp;</p>



<figure class="wp-block-image size-full"><img style="width:100% !important; height:auto !important; max-width:100% !important;" decoding="async" loading="lazy" src="https://blog.jetbrains.com/wp-content/uploads/2026/03/image9-1.png" alt="" class="wp-image-689343"/></figure>



<h2 class="wp-block-heading">Unused <code>Deferred</code></h2>



<p>Available since IntelliJ IDEA 2025.3</p>



<figure class="wp-block-image size-full"><img style="width:100% !important; height:auto !important; max-width:100% !important;" decoding="async" src="https://blog.jetbrains.com/wp-content/uploads/2026/03/image-29.png" alt="" class="wp-image-689126"/></figure>



<p>This inspection appears when you use async without ever using its result. In such cases, you should use launch instead. This is the key difference between launch and <code>async</code>: <code>async</code> returns a result and is expected to await this result, while <code>launch</code> produces no result.&nbsp;</p>



<p>Because of this, exception handling differs. <code>async</code> doesn’t call <code>CoroutineExceptionHandler</code> because it is expected to throw an exception from await and propagate it this way.&nbsp;</p>



<h2 class="wp-block-heading"><code>Job</code> used as an argument in a coroutine starter</h2>



<p>Available since IntelliJ IDEA 2025.3</p>



<figure class="wp-block-image size-full"><img style="width:100% !important; height:auto !important; max-width:100% !important;" decoding="async" loading="lazy" src="https://blog.jetbrains.com/wp-content/uploads/2026/03/image-33.png" alt="" class="wp-image-689227"/></figure>



<p>I’ve been looking forward to this inspection for years! Using <code>Job</code> as an argument to a coroutine starter causes issues, and it’s something I’ve seen in many projects. I covered this anti-pattern in my book and workshops, but it still appears quite often. This inspection should help clarify the correct approach. Let’s look at why <code>Job</code> shouldn’t be used as an argument for a coroutine.&nbsp;</p>



<p>The key misunderstanding here is that <code>Job</code> cannot be overridden by an argument. If you use any other context, it will be used in the coroutine and its children, but not <code>Job</code>. Every coroutine creates its own job. A job contains a coroutine’s state and relations – it cannot be shared or enforced from outside. The <code>Job</code> that is used as an argument isn’t going to be a job of this coroutine. Instead, it overrides <code>Job</code> from the scope and becomes a parent. This breaks structured concurrency.</p>



<p>For example: Using <code>withContext(SupervisorJob()) { … }</code> behaves very differently from <code>supervisorScope { … }</code>.&nbsp;</p>



<p><code>supervisorScope</code> creates a child coroutine of the caller of this function, and it uses a supervisor job (it doesn’t propagate its children’s exceptions). On the other hand, <code>withContext(SupervisorJob())</code> creates a regular coroutine, which is a child of <code>SupervisorJob</code> and has no relation to the caller.&nbsp;</p>



<p>Consider the code below. An exception in the first launch propagates to <code>withContext</code> (which uses regular <code>Job</code>), cancels the other child coroutines, and is then rethrown. <code>SupervisorJob()</code> has no effect. In some cases, it can even be harmful, as it breaks structured concurrency. If the caller of <code>withContext(SupervisorJob())</code> is cancelled, that cancellation won’t propagate, which will result in a memory leak.&nbsp;</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">import kotlinx.coroutines.*

val handler = CoroutineExceptionHandler { _, e ->
   println("Exception:  ${e.message}")
}

fun main(): Unit = runBlocking(handler) {
   // DON'T DO THAT!
   withContext(SupervisorJob()) {
       launch {
           delay(1000)
           throw Error("Some error")
       }
       launch {
           delay(2000)
           println("AAA")
       }
   }
  println("Done")
}
// (1 sec)
// Exception in thread "main"...</pre>



<figure class="wp-block-image size-full"><img style="width:100% !important; height:auto !important; max-width:100% !important;" decoding="async" loading="lazy" src="https://blog.jetbrains.com/wp-content/uploads/2026/03/image-30.png" alt="" class="wp-image-689146"/></figure>



<p>Using <code>supervisorScope</code> would prevent this problem:&nbsp;</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">import kotlinx.coroutines.*

val handler = CoroutineExceptionHandler { _, e ->
   println("Exception:  ${e.message}")
}

fun main(): Unit = runBlocking(handler) {
  supervisorScope {
      launch {
          delay(1000)
          throw Error("Some error")
      }
      launch {
          delay(2000)
          println("AAA")
      }
  }
  println("Done")
}
// (1 sec)
// Exception:  Some error
// (1 sec)
// AAA
// Done</pre>



<p>A <code>Job</code> used as an argument breaks the relationship with the caller. In the case below, <code>updateToken</code> won’t be related to the caller of <code>getToken</code>:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">suspend fun getToken(): Token = coroutineScope {
   val token = tokenRepository.fetchToken()
   launch(Job()) { // Poor practice
       tokenRepository.updateToken(token)
   }
   token
}</pre>



<p>This is generally discouraged, as it breaks structured concurrency. The standard approach would be to sequentially call <code>updateToken</code>:&nbsp;</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">suspend fun getToken(): Token {
   val token = tokenRepository.fetchToken()
   tokenRepository.updateToken(token)
   return token
}</pre>



<p>If we really want to detach <code>updateToken</code> from <code>getToken</code>, a better practice would be to start the launch on a different scope, like the backgroundScope we define in our application for background tasks. With this approach, the new coroutine is still attached to a scope, just a different one:&nbsp;</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">suspend fun getToken(): Token {
   val token = tokenRepository.fetchToken()
   backgroundScope.launch { // Acceptable
       tokenRepository.updateToken(token)
   }
   return token
}</pre>



<h2 class="wp-block-heading"><code>suspendCancellableCoroutine</code> instead of <code>suspendCoroutine</code></h2>



<p>Available since IntelliJ IDEA 2025.3</p>



<figure class="wp-block-image size-full"><img style="width:100% !important; height:auto !important; max-width:100% !important;" decoding="async" src="https://blog.jetbrains.com/wp-content/uploads/2026/03/image-32.png" alt="" class="wp-image-689233"/></figure>



<p>To suspend a coroutine, use <code>suspendCancellableCoroutine</code>. Its predecessor, <code>suspendCoroutine</code>, does not support cancellation and should be avoided.<br><code>suspendCancellableCoroutine</code> is a low-level API rarely used in application code, but often used by libraries that support suspending calls.&nbsp;</p>



<h2 class="wp-block-heading">Suspicious implicit <code>CoroutineScope</code> receiver</h2>



<p>Available since IntelliJ IDEA 2025.3, but this inspection is disabled by default and must be enabled manually.</p>



<figure class="wp-block-image size-full"><img style="width:100% !important; height:auto !important; max-width:100% !important;" decoding="async" loading="lazy" src="https://blog.jetbrains.com/wp-content/uploads/2026/03/image13.png" alt="" class="wp-image-689354"/></figure>



<p>Implicit receivers within lambdas can be confusing. In the above example, <code>async</code> calls are executed on the scope created by <code>coroutineScope</code> because <code>collectLatest</code> doesn’t provide its own scope. This can lead to memory leaks. When a new value reaches <code>collectLatest</code>, it should cancel processing of the previous one. In this example, it cannot cancel the <code>async</code> coroutines, as they are attached to <code>coroutineScope</code>, not to <code>collectLatest</code>. To avoid this, define <code>coroutineScope</code> inside <code>collectLatest</code>, not outside it. This inspection highlights such cases to prevent these issues.&nbsp;</p>



<figure class="wp-block-image size-full"><img style="width:100% !important; height:auto !important; max-width:100% !important;" decoding="async" src="https://blog.jetbrains.com/wp-content/uploads/2026/03/image-31.png" alt="" class="wp-image-689175"/></figure>



<h2 class="wp-block-heading">Simpler operations for flow processing</h2>



<p>Available since IntelliJ IDEA 2026.1 (currently in EAP)</p>



<figure class="wp-block-image size-full"><img style="width:100% !important; height:auto !important; max-width:100% !important;" decoding="async" loading="lazy" src="https://blog.jetbrains.com/wp-content/uploads/2026/03/image_1-1.png" alt="" class="wp-image-689366"/></figure>



<p>You may already know these from collection or sequence processing:<br>If you use <code>filterNotNull</code> after map, you’ll get the suggestion to use <code>mapNotNull</code>. If you use filter <code>{ it is T }</code>, the IDE will suggest using <code>filterNotNull&lt;T&gt;</code>.<br>These suggestions are now also available for flows!&nbsp;</p>



<h2 class="wp-block-heading">Summary</h2>



<p>IntelliJ IDEA continues to help you write better code – not only by advancing its AI tools and agents, but also by improving the core development experience. There are still many inspections I would love to see in the IDE, but the current set already brings significant value.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>IntelliJ IDEA 2025.3.4 is Out!</title>
		<link>https://blog.jetbrains.com/idea/2026/03/intellij-idea-2025-3-4/</link>
		
		<dc:creator><![CDATA[Julia Shashkova]]></dc:creator>
		<pubDate>Tue, 17 Mar 2026 17:25:08 +0000</pubDate>
		<featuredImage>https://blog.jetbrains.com/wp-content/uploads/2026/03/IJ-social-BlogFeatured-2025-3-4-1.png</featuredImage>		<category><![CDATA[releases]]></category>
		<category><![CDATA[bug-fix-update]]></category>
		<category><![CDATA[intellij-idea]]></category>
		<guid isPermaLink="false">https://blog.jetbrains.com/?post_type=idea&#038;p=688872</guid>

					<description><![CDATA[We’ve just released IntelliJ IDEA 2025.3.4. This update introduces full support for Java 26 along with several notable improvements. You can update to this version from inside the IDE, using the Toolbox App, or using snaps if you are a Ubuntu user. You can also download it from our website. Here are the most notable [&#8230;]]]></description>
										<content:encoded><![CDATA[
<p>We’ve just released IntelliJ IDEA 2025.3.4. This update introduces <strong>full support for Java 26</strong> along with several notable improvements.</p>



<p>You can update to this version from inside the IDE, using the <a href="https://www.jetbrains.com/toolbox-app/" target="_blank" rel="noopener">Toolbox App</a>, or using snaps if you are a Ubuntu user. You can also download it from our <a href="https://www.jetbrains.com/idea/download/" target="_blank" rel="noopener">website</a>.</p>



<p>Here are the most notable improvements:</p>



<ul>
<li>Resolved an issue where running an HTTP request could trigger a different request in the same file. [<a href="https://youtrack.jetbrains.com/issue/IJPL-66727" target="_blank" rel="noopener">IJPL-66727</a>]</li>



<li>Local changes refresh in large Perforce projects now works as expected. [<a href="https://youtrack.jetbrains.com/issue/IJPL-236557" target="_blank" rel="noopener">IJPL-236557</a>]</li>



<li>The <em>Dependencies</em> tab now opens correctly when using the <em>Analyze Cyclic Dependencies</em> feature. [<a href="https://youtrack.jetbrains.com/issue/IJPL-206236" target="_blank" rel="noopener">IJPL-206236</a>]</li>
</ul>



<p>For a comprehensive overview of the fixes, see the <a href="https://youtrack.jetbrains.com/articles/IDEA-A-2100662645" data-type="link" data-id="https://youtrack.jetbrains.com/articles/IDEA-A-2100662645" target="_blank" rel="noopener">release notes</a>. If you spot any issues, let us know via the <a href="https://youtrack.jetbrains.com/issues/IDEA" target="_blank" rel="noreferrer noopener">issue tracker</a>.</p>



<p>Happy developing!</p>



<p></p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Java 26 in IntelliJ IDEA</title>
		<link>https://blog.jetbrains.com/idea/2026/03/java-26-in-intellij-idea/</link>
		
		<dc:creator><![CDATA[Marit van Dijk]]></dc:creator>
		<pubDate>Tue, 17 Mar 2026 14:17:33 +0000</pubDate>
		<featuredImage>https://blog.jetbrains.com/wp-content/uploads/2026/03/Blog-Social-Share-image-and-Featured-1280x720-1-1.png</featuredImage>		<category><![CDATA[idea]]></category>
		<category><![CDATA[java]]></category>
		<category><![CDATA[intellij-idea]]></category>
		<category><![CDATA[java-26]]></category>
		<guid isPermaLink="false">https://blog.jetbrains.com/?post_type=idea&#038;p=687833</guid>

					<description><![CDATA[The Java release cadence means we get a new Java version every six months. Java 26 was released on March 17, 2026. At JetBrains, we are committed to supporting the latest technologies in IntelliJ IDEA and adding useful enhancements for both stable and preview features. In this blog post, we will give you an overview [&#8230;]]]></description>
										<content:encoded><![CDATA[
<p>The Java release cadence means we get a new Java version every six months. Java 26 was released on March 17, 2026. At JetBrains, we are committed to supporting the latest technologies in IntelliJ IDEA and adding useful enhancements for both stable and preview features. In this blog post, we will give you an overview of what Java 26 delivers and how it is supported in IntelliJ IDEA.</p>



<p><a href="https://openjdk.org/projects/jdk/26/" target="_blank" rel="noopener">Java 26</a> delivers ten JEPs, of which five are final. There are no new stable language features in this release, but there are meaningful performance improvements and new library additions. In addition, several preview features continue to mature.&nbsp;</p>



<p>We are also happy to share that a JetBrains colleague contributed a small but useful improvement to the Java platform.</p>



<p>Before diving in, let&#8217;s start by setting up IntelliJ IDEA to use Java 26.</p>



<h2 class="wp-block-heading"><strong>Using Java 26 in IntelliJ IDEA (setup)</strong></h2>



<p>Java 26 support is available in IntelliJ IDEA.</p>



<p>To use Java 26, you will need to download the JDK. You can do so from inside IntelliJ IDEA or by using tools like <a href="https://sdkman.io/" target="_blank" rel="noopener">SDKMAN!</a>&nbsp;</p>



<p>To download a JDK from IntelliJ IDEA, open the <em>Project Structure</em>, go to the tab <em>Project Settings | Project</em>, open the drop-down menu in the <em>SDK</em> field, and select <em>Download JDK</em>. In the <em>Download JDK</em> popup that opens, set <em>Version</em> to <em>26</em>, and in the <em>Vendor</em> field, select the vendor you want to use.</p>



<p>Note that you can also download early access builds from inside IntelliJ IDEA. For example, Java 26 also introduced a new build of Project Valhalla, which is also available for download.</p>



<figure class="wp-block-image size-full"><img style="width:100% !important; height:auto !important; max-width:100% !important;" decoding="async" loading="lazy" src="https://blog.jetbrains.com/wp-content/uploads/2026/03/Download-JDK-26-Valhalla.png" alt="" class="wp-image-687923"/><figcaption class="wp-element-caption"><em>Download JDK 26 Valhalla Early Access</em></figcaption></figure>



<p>IntelliJ IDEA already has support for <a href="https://openjdk.org/projects/valhalla/value-objects" target="_blank" rel="noopener">value classes</a> from Project Valhalla, as demonstrated in the What&#8217;s New In IntelliJ IDEA 2025.3 video:</p>



<figure class="wp-block-embed is-type-video is-provider-youtube wp-block-embed-youtube wp-embed-aspect-16-9 wp-has-aspect-ratio"><div class="wp-block-embed__wrapper">
<iframe loading="lazy" title="What&#039;s New In IntelliJ IDEA 2025.3" src="https://www.youtube.com/embed/YdAgkSNljTk?start=1590&#038;feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe>
</div><figcaption class="wp-element-caption"><em>What&#8217;s New In IntelliJ IDEA 2025.3</em> <em>&#8211; Java 26 Valhalla Early Access value type support</em></figcaption></figure>



<p>If you use<a href="https://sdkman.io/" target="_blank" rel="noopener"> SDKMAN!</a> or<a href="https://asdf-vm.com/" target="_blank" rel="noopener"> asdf</a> to manage your JDKs, IntelliJ IDEA can read the <code>.sdkmanrc</code> or <code>.tool-versions</code> file in your project and configure the JDK automatically when you open the file. For example, if you are using SDKMAN! and the JDK version specified in the <code>.sdkmanrc</code> file is not yet installed, an inlay hint will appear in the file, allowing you to download it directly from the IDE by running the relevant SDKMAN! command.&nbsp;</p>



<figure class="wp-block-image size-full"><img style="width:100% !important; height:auto !important; max-width:100% !important;" decoding="async" loading="lazy" src="https://blog.jetbrains.com/wp-content/uploads/2026/03/Run-sdk-install-java-26-1.png" alt="" class="wp-image-687945"/><figcaption class="wp-element-caption"><em>Run sdk install java 26</em></figcaption></figure>



<p>If it is already installed but not yet configured for the project, there will be an inlay hint <em>Set as project JDK</em>. Click the inlay hint to set the mentioned JDK version for the project. Once set, there will be an inlay hint <em>Project JDK (26)</em>. Click the link to open the <em>Project Structure</em> popup where the SDK is set.</p>



<figure class="wp-block-video"><video controls src="https://blog.jetbrains.com/wp-content/uploads/2026/03/SDKMAN-Set-Project-SDK.mp4"></video><figcaption class="wp-element-caption"><em>Set project SDK using .sdkmanrc</em></figcaption></figure>



<p>Make sure to configure IntelliJ IDEA to use the right language level. To use Java 26 stable features, set <em>Language level</em> to <em>26 &#8211; No new language features</em>. As mentioned, Java 26 introduces no new stable language features, hence this description.</p>



<figure class="wp-block-image size-full"><img style="width:100% !important; height:auto !important; max-width:100% !important;" decoding="async" loading="lazy" src="https://blog.jetbrains.com/wp-content/uploads/2026/03/Language-Level-26-No-new-language-features.png" alt="" class="wp-image-687978"/><figcaption class="wp-element-caption"><em>Language Level: 26 &#8211; No new language features</em></figcaption></figure>



<p>To try out preview features, set <em>Language level</em> to <em>26 (Preview) &#8211; Primitive types in patterns (4th preview)</em>. Setting the right language level means that IntelliJ IDEA will show support for this language level in the editor, including inspections and quick-fixes. Usage of preview features will be highlighted as such, as you might not want to use preview features in production code yet.</p>



<figure class="wp-block-image size-full"><img style="width:100% !important; height:auto !important; max-width:100% !important;" decoding="async" loading="lazy" src="https://blog.jetbrains.com/wp-content/uploads/2026/03/Language-Level-26-Preview.png" alt="" class="wp-image-687989"/><figcaption class="wp-element-caption"><em>Language Level: 26 (Preview) &#8211; Primitive types in patterns (4th preview)</em></figcaption></figure>



<p>When you set the language level to Java 26 (either stable or preview), IntelliJ IDEA will show you all relevant inspections. To see which inspections were added in the last version of IntelliJ IDEA, open <em>Settings</em> | <em>Editor</em> | <em>Inspections</em>, click on the <em>Filter Inspections</em> button, and select <em>Show New Inspections in IDEA 2026.1</em>.</p>



<figure class="wp-block-video"><video controls src="https://blog.jetbrains.com/wp-content/uploads/2026/03/New-inspections.mp4"></video><figcaption class="wp-element-caption"><em>New Inspections in IDEA 2026.1</em></figcaption></figure>



<p>A full list of inspections is available on <a href="https://www.jetbrains.com/help/inspectopedia/WhatIsNewInspections.html" target="_blank" rel="noopener">Inspectopedia</a>. In upcoming releases of IntelliJ IDEA, we will continue to add more inspections for Java language support, based on current and new language features.</p>



<h2 class="wp-block-heading"><strong>New stable features in Java 26</strong></h2>



<p>Let&#8217;s take a quick look at the features Java 26 introduces.</p>



<h3 class="wp-block-heading"><a href="https://openjdk.org/jeps/516" target="_blank" rel="noopener"><strong>JEP 516: Ahead-of-Time Object Caching with Any GC</strong></a></h3>



<p>Java continues to improve startup time and warmup performance, as part of <a href="https://openjdk.org/projects/leyden/" target="_blank" rel="noopener">Project Leyden</a>. JEP 516 extends the HotSpot JVM&#8217;s ahead-of-time (AOT) cache to work with any garbage collector, including the low-latency ZGC, by storing cached Java objects in a GC-agnostic format and loading them sequentially into memory at startup.</p>



<h3 class="wp-block-heading" id="http"><a href="https://openjdk.org/jeps/517" target="_blank" rel="noopener"><strong>JEP 517: HTTP/3 for the HTTP Client API</strong></a></h3>



<p>Update the HTTP Client API, introduced in Java 11, to support the HTTP/3 protocol, to make it possible for libraries and applications to interact with HTTP/3 servers with minimal changes to the code. This allows applications using the HTTP Client API to benefit from improvements offered by the HTTP/3 protocol, such as potentially faster handshakes, more reliable transport, and avoidance of network congestion issues. The HTTP/3 protocol is already supported by most web browsers and almost 40% of all websites.</p>



<h3 class="wp-block-heading"><a href="https://openjdk.org/jeps/522" target="_blank" rel="noopener"><strong>JEP 522: G1 GC: Improve Throughput by Reducing Synchronization</strong></a></h3>



<p>This JEP improves application throughput for applications using the G1 garbage collector by reducing the synchronization required between application threads and GC threads.</p>



<h3 class="wp-block-heading"><a href="https://openjdk.org/jeps/500" target="_blank" rel="noopener"><strong>JEP 500: Prepare to Make Final Mean Final</strong></a></h3>



<p>JDK 26 introduces warnings when deep reflection is used to mutate a <code>final</code> field, aiming to prepare developers for a future release where <code>final</code> truly means <code>final</code>, making Java programs both safer and potentially faster. Applications that rely on this pattern can update their code ahead of the eventual restriction, or selectively opt back in where truly needed.</p>



<h3 class="wp-block-heading"><a href="https://openjdk.org/jeps/504" target="_blank" rel="noopener"><strong>JEP 504: Remove the Applet API</strong></a></h3>



<p>The Applet API, deprecated for removal since JDK 17, has been removed. Neither modern browsers nor recent JDK releases still support applets.</p>



<h2 class="wp-block-heading"><strong>Preview features in Java 26</strong></h2>



<p>With Java’s release cadence of six months, new language features are often released as preview features. This gives developers a chance to try out new features and provide their feedback before these features become final. A preview feature may go through multiple rounds, either with or without changes, before it is finalized as a standard part of the language.</p>



<p>IntelliJ IDEA strives to support preview features, allowing you to experiment with them before they become final. Because of how these features work, IntelliJ IDEA is committed to only supporting preview features for the current JDK. To enable preview features, set <em>Language level</em> to <em>26 (Preview) &#8211; Primitive types in patterns (4th preview)</em>.</p>



<p>Java 26 contains four preview features and one incubator feature. There are several changes to the preview features in Java 26, compared to Java 25.</p>



<h3 class="wp-block-heading"><a href="https://openjdk.org/jeps/530" target="_blank" rel="noopener"><strong>JEP 530: Primitive Types in Patterns, instanceof, and switch (Fourth Preview)</strong></a></h3>



<p>This feature enhances pattern matching to support all primitive types in pattern contexts, including <code>instanceof</code> and <code>switch</code>. This feature lifts some of the existing limitations in pattern matching, making it possible to match, test, and safely convert primitive values in these constructs. Removing the need for unsafe manual casts (which might cause subtle bugs) and range checks, this feature improves code safety and readability. This feature is previewed again, with some changes since Java 25, which add some constraints (see <a href="https://openjdk.org/jeps/530" target="_blank" rel="noopener">JEP</a> for details).&nbsp;</p>



<p>For a <a href="https://blog.jetbrains.com/idea/2025/03/java-24-and-intellij-idea/#a-quick-example">quick example</a> of using primitive types in switch expressions with guard patterns, see <a href="https://blog.jetbrains.com/idea/2025/03/java-24-and-intellij-idea/#primitive-types-in-patterns,-instanceof,-and-switch-preview-feature">Java 24 and IntelliJ IDEA</a>. For a longer explanation of the feature, see the section <a href="https://blog.jetbrains.com/idea/2024/09/java-23-and-intellij-idea/#primitive-types-in-patterns,-instanceof,-and-switch-preview-feature">Primitive Types in Patterns, instanceof, and switch (Preview Feature)</a> in <a href="https://blog.jetbrains.com/idea/2024/09/java-23-and-intellij-idea/">Java 23 and IntelliJ IDEA</a>. Note that there are some changes to this feature in the latest preview.</p>



<p>For more background information on this feature, watch the following video:</p>



<figure class="wp-block-embed is-type-video is-provider-youtube wp-block-embed-youtube wp-embed-aspect-16-9 wp-has-aspect-ratio"><div class="wp-block-embed__wrapper">
<iframe loading="lazy" title="JEP Explained. JEP 455: Primitive Types in Patterns, instanceof, and switch" src="https://www.youtube.com/embed/tqBV4MZ-qSM?feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe>
</div><figcaption class="wp-element-caption"><em>JEP Explained. JEP 455: Primitive Types in Patterns, instanceof, and switch</em></figcaption></figure>



<h3 class="wp-block-heading"><a href="https://openjdk.org/jeps/526" target="_blank" rel="noopener"><strong>JEP 526: Lazy Constants (Second Preview)</strong></a></h3>



<p>As Java programmers, we are aware that we should strive for immutability, as it offers many benefits. Since an immutable object can be in only one state, it can be safely shared across multiple threads. The current way to manage immutability is to declare fields final. However, final fields must be set eagerly, either during construction for instance fields or during class initialization for static fields. This initialization leads to longer startup times and might not even be necessary if the fields are not actually used.&nbsp;</p>



<p>Lazy constants offer greater flexibility as to the timing of their initialization. They are, as the name implies, initialized lazily. A lazy constant is a <code>java.lang.LazyConstant </code>object holding a single immutable value that is set only when first needed. The JVM treats them as true constants and applies the same performance optimizations.</p>



<p>To be eligible for constant folding (the process of simplifying constant expressions at compile time), a lazy constant must be stored in a final field. IntelliJ IDEA 2026.1 adds an inspection and quick-fix to make a <code>LazyConstant</code> final.</p>



<figure class="wp-block-image size-full"><img style="width:100% !important; height:auto !important; max-width:100% !important;" decoding="async" loading="lazy" src="https://blog.jetbrains.com/wp-content/uploads/2026/03/Make-LazyConstant-final.png" alt="" class="wp-image-688011"/><figcaption class="wp-element-caption"><em>Make LazyConstant final</em></figcaption></figure>



<p>There are some changes to this feature compared to Java 25, mainly focusing on high-level use cases, removing low-level methods, and renaming the feature accordingly – from stable values to lazy constants.</p>



<h3 class="wp-block-heading"><a href="https://openjdk.org/jeps/525" target="_blank" rel="noopener"><strong>JEP 525: Structured Concurrency (Sixth Preview)</strong></a></h3>



<p>Structured concurrency gives us better &#8220;idioms&#8221; for multithreaded code, which expresses the synchronous way of thinking. This makes concurrent code easier to understand and reason about. In addition, it helps to eliminate thread leaks and cancellation delays. It treats a group of related tasks running in different threads as a single unit of work, improving observability, cancellation, and error handling in concurrent code.&nbsp;</p>



<p>IntelliJ IDEA has a live template <code>sts</code> to add structured concurrency to your code. If you know a live template exists, you can use it by name.&nbsp;</p>



<figure class="wp-block-video"><video controls src="https://blog.jetbrains.com/wp-content/uploads/2026/03/Insert-live-template-sts.mp4"></video><figcaption class="wp-element-caption"><em>Insert live template sts for structured concurrency</em></figcaption></figure>



<p>IntelliJ IDEA 2026.1 includes some improvements to the debugger regarding virtual threads. Virtual threads are grouped into containers representing their scopes, making it easy to see which threads are virtual and which are platform threads. Any virtual thread without its own container is placed under the Root container. This grouping is new and gives you a clear view of the structure in structured concurrency.</p>



<figure class="wp-block-video"><video controls src="https://blog.jetbrains.com/wp-content/uploads/2026/03/Get-Thread-Dump-with-Debugger.mp4"></video><figcaption class="wp-element-caption">Get Thread Dump with Debugger</figcaption></figure>



<p>For background information on structured concurrency, watch the following video:</p>



<figure class="wp-block-embed is-type-video is-provider-youtube wp-block-embed-youtube wp-embed-aspect-16-9 wp-has-aspect-ratio"><div class="wp-block-embed__wrapper">
<iframe loading="lazy" title="JEP Explained. JEP 480: Structured Concurrency" src="https://www.youtube.com/embed/K-LyK5LU3mM?feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe>
</div><figcaption class="wp-element-caption"><em>JEP Explained. JEP 480: Structured Concurrency</em></figcaption></figure>



<p>Note that there have been changes to this preview feature since the video was recorded.</p>



<h3 class="wp-block-heading"><a href="https://openjdk.org/jeps/524" target="_blank" rel="noopener"><strong>JEP 524: PEM Encodings of Cryptographic Objects (Second Preview)</strong></a></h3>



<p>This JEP provides a preview API for encoding and decoding cryptographic objects to/from the Privacy-Enhanced Mail (PEM) format. The second preview contains some changes compared to the previous version.</p>



<h2 class="wp-block-heading"><strong>Incubator features in Java 26</strong></h2>



<p>Incubator features are experimental APIs made available for developers to try out and provide feedback on. Unlike preview features, incubator APIs may change significantly or even be removed in future releases and are not intended for production use.</p>



<p>To use an incubator feature, you’ll need to explicitly add the module while you run it. To use Vector API, add the following: <code>--add-modules jdk.incubator.vector</code>.</p>



<p>If you are running your program from IntelliJ IDEA, you can add this to the run configurations for your application. Select the run configuration for your program and click the three dots for <em>More Actions</em>. Select <em>Edit…</em> to open the <em>Run/Debug Configurations</em>. Click the link <em>Modify Options</em>, and in the <em>Add Run Options</em> popup, select <em>Add VM Options</em>. A new field will appear with the hint <em>VM Options</em>. Add the option <code>--add-modules jdk.incubator.vector</code> to that field.</p>



<figure class="wp-block-video"><video controls src="https://blog.jetbrains.com/wp-content/uploads/2026/03/Add-VM-Options.mp4"></video><figcaption class="wp-element-caption"><em>Add VM Options</em></figcaption></figure>



<h3 class="wp-block-heading"><a href="https://openjdk.org/jeps/529" target="_blank" rel="noopener"><strong>JEP 529: Vector API (Eleventh Incubator)</strong></a></h3>



<p>This JEP introduces an API that allows developers to express vector computations that reliably compile to optimal vector instructions on supported CPUs. Vector operations enable more work to be performed in a single CPU cycle, which can result in significant performance gains.&nbsp;</p>



<p>This eleventh incubator contains no substantial changes compared to the previous version. The Vector API will continue to incubate until the necessary features from <a href="https://openjdk.org/projects/valhalla/" target="_blank" rel="noopener">Project Valhalla</a> are available, at which point it will be adapted and promoted to preview.</p>



<p>For background information on Vector API, watch the following video:</p>



<figure class="wp-block-embed is-type-video is-provider-youtube wp-block-embed-youtube wp-embed-aspect-16-9 wp-has-aspect-ratio"><div class="wp-block-embed__wrapper">
<iframe loading="lazy" title="JEP Explained. JEP 469: Vector API" src="https://www.youtube.com/embed/_C3adaExyi0?feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe>
</div><figcaption class="wp-element-caption"><em>JEP Explained. JEP 469: Vector API&nbsp;</em></figcaption></figure>



<h2 class="wp-block-heading"><strong>Contributions to the Java platform</strong></h2>



<p>When we spot an opportunity to make Java safer or less error-prone, we, of course, try to provide useful features in IntelliJ IDEA to help you write better code. But we also try to contribute improvements back to the platform.</p>



<p>Our colleague<a href="https://github.com/amaembo" target="_blank" rel="noopener"> Tagir Valeev</a> – author of<a href="https://www.manning.com/books/100-java-mistakes-and-how-to-avoid-them" target="_blank" rel="noopener"> <em>100 Java Mistakes and How to Avoid Them</em></a> – <a href="https://github.com/openjdk/jdk/commit/48d394a245e7d16423b3829efa326fe72605c8ee" target="_blank" rel="noopener">contributed</a> two new default methods to <code>java.util.Comparator: min(T, T)</code> and <code>max(T, T)</code>. These make it straightforward to find the lesser or greater of two objects using a given comparator, without needing verbose workarounds. You can find more details in<a href="https://bugs.openjdk.org/browse/JDK-8356995" target="_blank" rel="noopener"> JDK-8356995</a>. We are happy to see this change accepted into the platform!</p>



<h2 class="wp-block-heading"><strong>Conclusion</strong></h2>



<p>Java 26 may not be an LTS release, but it brings meaningful performance improvements, useful library additions, and continues to evolve several important preview features. IntelliJ IDEA supports Java 26 from day one, so you can start taking advantage of everything this release has to offer right away.</p>



<p>IntelliJ IDEA will continue to support the latest Java features. As always, please let us know if you have any feedback.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Koog Comes to Java: The Enterprise AI Agent Framework From JetBrains</title>
		<link>https://blog.jetbrains.com/ai/2026/03/koog-comes-to-java/</link>
		
		<dc:creator><![CDATA[Vadim Briliantov]]></dc:creator>
		<pubDate>Tue, 17 Mar 2026 09:57:20 +0000</pubDate>
		<featuredImage>https://blog.jetbrains.com/wp-content/uploads/2026/03/KG-social-BlogFeatured-1280x720-1-1.png</featuredImage>		<product ><![CDATA[idea]]></product>
		<category><![CDATA[ai]]></category>
		<category><![CDATA[ecosystem]]></category>
		<category><![CDATA[java]]></category>
		<guid isPermaLink="false">https://blog.jetbrains.com/?post_type=ai&#038;p=684968</guid>

					<description><![CDATA[Adding AI agents to your enterprise backend shouldn&#8217;t mean compromising your architecture. If your core systems are built in Java, orchestrating LLMs shouldn&#8217;t require you to introduce separate Python microservices or rewrite your stack. Today, we are launching Koog for Java. Originally built to keep pace as JetBrains scaled up its own activities, Koog replaces [&#8230;]]]></description>
										<content:encoded><![CDATA[
<p>Adding AI agents to your enterprise backend shouldn&#8217;t mean compromising your architecture. If your core systems are built in Java, orchestrating LLMs shouldn&#8217;t require you to introduce separate Python microservices or rewrite your stack.</p>



<p>Today, we are launching <a href="https://www.jetbrains.com/koog/" target="_blank" rel="noreferrer noopener">Koog for Java</a>. Originally built to keep pace as JetBrains scaled up its own activities, Koog replaces unpredictable, ad hoc prompt changing with structured, observable, and fault-tolerant agent workflows.</p>



<p>Now, one of the JVM&#8217;s most powerful agent frameworks comes with a fully idiomatic Java API. Your Java teams can build reliable AI agents directly inside your existing backends, with fluent builder-style APIs, thread pool executors, and native Java abstractions – completely free of Kotlin-specific friction.</p>



<h3 class="wp-block-heading"><strong>What you get with Koog for Java</strong></h3>



<p>The Java API provides access to all of Koog&#8217;s features:</p>



<ul>
<li><strong>Multiple workflow strategies</strong> (functional, graph-based, and planning): Control exactly how your agent executes tasks.</li>



<li><strong>Spring Boot integration</strong>: Drop Koog into your existing Spring applications.</li>



<li><strong>Support for all major LLM providers</strong>: Use your preferred models from OpenAI, Anthropic, Google, DeepSeek, Ollama, and more.</li>



<li><strong>Fault tolerance with Persistence</strong>: Recover from failures without losing progress or repeating expensive LLM calls.</li>



<li><strong>Observability with OpenTelemetry</strong>: Get full visibility into agent execution, token usage, and costs, with Langfuse and W&amp;B Weave support out of the box</li>



<li><strong>History compression</strong>: Reduce token usage and optimize costs at scale</li>



<li><strong>And much more!</strong></li>
</ul>



<p>Read on to see what building agents in Java with Koog looks like.</p>



<h3 class="wp-block-heading"><strong>Simple setup</strong></h3>



<p>AI agents work by connecting large language models (LLMs) with functions from your application, which are generally referred to as &#8220;tools&#8221;. The LLM decides which tools to call and when, based on the task you give it. Building an agent in Java starts with defining these tools. Annotate your existing Java methods with <code>@Tool</code> and add descriptions so the LLM understands what each function does:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="java" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">public class BankingTools implements ToolSet {
    @Tool
    @LLMDescription("Sends money to a recipient")
    public Boolean sendMoney(
        @LLMDescription("Unique identifier of the recipient")
        String recipientId,
        Integer amount
    ) {
        return true; // Your implementation here
    }

    @Tool
    @LLMDescription("Account balance in $")
    public Integer getAccountBalance(String userId) {
        return 1000000; // Your implementation here
    }
}</pre>



<p>Next, create an agent using the builder API. You&#8217;ll need to configure which LLM providers to use (OpenAI, Anthropic, etc.), set a system prompt that defines the agent&#8217;s role, and register your tools:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="java" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">// Connect to one or more LLM providers
var promptExecutor = new MultiLLMPromptExecutor(
    new OpenAILLMClient("OPENAI_API_KEY"),
    new AnthropicLLMClient("ANTHROPIC_API_KEY")
);

// Build the agent
var bankingAgent = AIAgent.builder()
    .promptExecutor(promptExecutor)
    .llmModel(OpenAIModels.Chat.GPT5_2)  // Choose which model to use
    .systemPrompt("You're a banking assistant")  // Define the agent's role
    .toolRegistry(
        ToolRegistry.builder()
            .tools(new BankingTools())  // Register your tools
            .build()
    )
    .build();

// Run the agent with a user task
bankingAgent.run("Send 100$ to my friend Mike (mike_1234) if I have enough money");
</pre>



<p>When you run this agent, it will:</p>



<ol>
<li>Check the account balance using <code>getAccountBalance()</code></li>



<li>If there&#8217;s enough money, call <code>sendMoney()</code> with the right parameters</li>



<li>Return a response to the user</li>
</ol>



<p>This connects your Java application&#8217;s functionality with a fully autonomous AI agent that can reason about which actions to take.</p>



<h3 class="wp-block-heading"><strong>Predictable workflows with custom strategies</strong></h3>



<p>The simple example above lets the LLM decide everything – which tools to call and in what order. But for production systems, you often need more control. What if you want to ensure certain operations happen before others? Or limit which tools are available at each step? Or implement verification loops?</p>



<p>Koog provides different approaches to defining agent workflows: functional (code-based), graph-based, and planning-based.</p>



<p><strong>Functional strategies</strong> let you orchestrate individual agentic steps in code. Think of it like writing a regular Java method, but each step can involve LLM calls and tool executions. You split large tasks into smaller subtasks, each with its own prompt, limited set of tools, and type-safe inputs/outputs:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="java" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">var functionalAgent = AIAgent.builder()
    .promptExecutor(promptExecutor)
    .functionalStrategy("my-strategy", (ctx, userInput) -> {
        // Step 1: First, identify the problem
        // Only give the agent communication and read-only database access here
        ProblemDescription problem = ctx
            .subtask("Identify the problem: $userInput")
            .withOutput(ProblemDescription.class)  // Type-safe output
            .withTools(communicationTools, databaseReadTools)  // Limited tools
            .run();

        // Step 2: Now solve the problem
        // Give the agent database write access only after problem identification
        ProblemSolution solution = ctx
            .subtask("Solve the problem: $problem") // Use output from step 1
            .withOutput(ProblemSolution.class)
            .withTools(databaseReadTools, databaseWriteTools)
            .run();

        // Verify the solution and try to fix it until the solution is satisfying
        while (true) {
            var verificationResult = ctx
                .subtask("Now verify that the problem is actually solved: $solution")
                .withVerification()
                .withTools(communicationTools, databaseReadTools)
                .run();

            if (verificationResult.isSuccessful()) {
                return problemSolution;
            } else {
                problemSolution = ctx
                    .subtask("Fix the solution based on the provided feedback: ${verificationResult.getFeedback()}")
                    .withOutput(ProblemSolution.class)
                    .withTools(databaseReadTools, databaseWriteTools)
                    .run();
            }
        }

    })
    .build();</pre>



<p>This approach gives you the flexibility of code while still using AI agents for individual steps. Notice how you control the order of operations and which tools are available at each step. You can check the full runnable example <a href="https://github.com/JetBrains/koog/blob/develop/examples/simple-examples-java/src/main/java/ai/koog/agents/example/strategies/functional/FunctionalStrategyExample.java" target="_blank" rel="noopener">here</a>.</p>



<p><strong>Graph strategies</strong> define workflows as finite state machines with type-safe nodes and edges. Unlike functional strategies, graph strategies separate the logic (nodes and edges) from its execution. This enables powerful features like fine-grained persistence – if your agent crashes, it can resume from the exact node where it stopped, not from the beginning:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="java" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">var graphAgent = AIAgent.builder()
    .graphStrategy(builder -> {
        // Define the overall graph structure
        var graph = builder
            .withInput(String.class)
            .withOutput(ProblemSolution.class);

        // Define workflow elements: individual nodes (steps) and subgraphs
        var identifyProblem = AIAgentSubgraph.builder()
            .withInput(String.class)
            .withOutput(ProblemDescription.class)
            .limitedTools(communicationTools, databaseReadTools)
            .withTask(input -> "Identify the problem")
            .build();

        var solveProblem = … // subgraph for solving a problem
        
        var verifySolution = … // subgraph for verifying a solution
        
        var fix = ...// subgraph for fixing a problem

        // Connect the nodes with edges to define execution flow
        graph.edge(graph.nodeStart, identifyProblem);
        graph.edge(identifyProblem, solveProblem);
        graph.edge(solveProblem, verifySolution);

        // Conditional edges: if verification succeeds, finish; otherwise, attempt a fix
        graph.edge(AIAgentEdge.builder()
        	.from(verifySolution)
        	.to(graph.nodeFinish)
        	.onCondition(CriticResult::isSuccessful)
        	.transformed(CriticResult::getInput)
        	.build());

        graph.edge(AIAgentEdge.builder()
        	.from(verifySolution)
        	.to(fix)
        	.onCondition(verification -> !verification.isSuccessful())
        	.transformed(CriticResult::getFeedback)
        	.build());

        graph.edge(fix, verifySolution);

        return graph.build();
    })
    .build();</pre>



<p>Graph strategies are ideal when you need persistence, complex branching logic, or want to visualize your agent&#8217;s workflow. You can share the visualization and discuss it with your ML colleagues:</p>



<figure class="wp-block-image size-full"><img style="width:100% !important; height:auto !important; max-width:100% !important;" decoding="async" loading="lazy" src="https://blog.jetbrains.com/wp-content/uploads/2026/03/diagram.png" alt="" class="wp-image-688633"/></figure>



<p>Each node is type-safe, ensuring that the outputs from one node match the expected inputs of the next. You can find the full example <a href="https://github.com/JetBrains/koog/blob/develop/examples/simple-examples-java/src/main/java/ai/koog/agents/example/strategies/GraphStrategyExample.java" target="_blank" rel="noopener">here</a>.</p>



<p><strong>Planning strategies</strong> use goal-oriented action planning (GOAP) or LLM-based planning. Instead of defining the exact execution order, you define:</p>



<ul>
<li>Available actions with their preconditions (when they can run)</li>



<li>Effects (what they change in the agent&#8217;s state)</li>



<li>A goal condition (what the agent should achieve)</li>
</ul>



<p>The planner automatically figures out the optimal order for executing actions to reach the goal. This is powerful for complex scenarios where multiple paths might work, or when requirements change dynamically. See a detailed example <a href="https://github.com/JetBrains/koog/blob/develop/examples/simple-examples-java/src/main/java/ai/koog/agents/example/strategies/GoapStrategyExample.java" target="_blank" rel="noopener">here</a>.</p>



<h3 class="wp-block-heading"><strong>Persistence for fault tolerance</strong></h3>



<p>AI agents often handle complex, multi-step tasks that can take seconds or even minutes. During this time, servers can crash, network connections can fail, or deployments can happen. Without persistence, your agent would have to start all over again, wasting time and money on repeated LLM calls.</p>



<p>Koog&#8217;s persistence feature saves agent state to disk, S3, or a database after each step. If something fails, the graph-based agent can resume from exactly where it stopped, not from the beginning. It will restore at the last individual node and preserve all progress made before the failure:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="java" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">// First, configure where to store checkpoints
// Can be Postgres, S3, local disk, or your own implementation
var storage = new PostgresJdbcPersistenceStorageProvider(
    dataSource = dataSource,
    tableName = “banking_agent_checkpoints”
)

// Install the Persistence feature on your agent
var recoverableAgent = AIAgent.builder()
    // ... other agent configuration
    .install(Persistence.Feature, config -> {
        config.setStorage(storage);
        config.setEnableAutomaticPersistence(true);  // Auto-save after each step
    })
    .build();

// First run - starts fresh
recoverableAgent.run("Help me with my account", "user-session-0123");

// If a crash happens mid-execution...

// Second run with same session ID - automatically recovers and continues
recoverableAgent.run("Help me with my account", "user-session-0123");</pre>



<p>The session ID ties checkpoint data to a specific user session (like a user ID or request ID). This lets you run multiple agent instances simultaneously without conflicts.</p>



<h3 class="wp-block-heading"><strong>Observability with OpenTelemetry</strong></h3>



<p>When running agents in production, you need visibility into what they&#8217;re doing. Which tools did they call? How many tokens did each LLM request use? Where are the bottlenecks? Where did costs come from?</p>



<p>Koog integrates with OpenTelemetry to provide this visibility. Connect to backends like <a href="https://docs.koog.ai/opentelemetry-langfuse-exporter/" data-type="link" data-id="https://docs.koog.ai/opentelemetry-langfuse-exporter/" target="_blank" rel="noopener">Langfuse</a> or <a href="https://docs.koog.ai/opentelemetry-weave-exporter/" target="_blank" rel="noopener">W&amp;B Weave</a> to see detailed traces of agent execution, including nested events (nodes, tool calls, and LLM requests), token counts, costs, and timing information:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="java" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">var observableAgent = AIAgent.builder()
    // ... other agent configuration
    .install(OpenTelemetry.Feature, config -> {
        // Export telemetry data to your observability backend
        config.addSpanExporter(OtlpGrpcSpanExporter.builder()
            .setEndpoint("http://localhost:4317")  // Your OpenTelemetry collector
            .build());
    })
    .build();</pre>



<p>Once configured, every agent run automatically generates detailed traces that you can explore in your observability tool.</p>



<h3 class="wp-block-heading"><strong>History compression</strong></h3>



<p>As agents work on complex tasks, their conversation history grows with every LLM call and tool invocation. This history is sent with each subsequent request to provide context. But longer context means:</p>



<ul>
<li>Slower LLM responses</li>



<li>Higher costs (you pay per token)</li>



<li>Eventually hitting context window limits</li>
</ul>



<p>Koog&#8217;s history compression solves this by intelligently summarizing or extracting key information from the history, reducing token usage while preserving what&#8217;s important:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="java" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">var agentWithCompression = AIAgent.builder()
    .functionalStrategy("compressed", (ctx, userInput) -> {
        var response = ctx.requestLLM(userInput);
        // Your agent logic...

        // When history gets long, compress it
        ctx.compressHistory();
    })
    .build();</pre>



<p>You can customize how compression works:</p>



<ul>
<li><code>HistoryCompressionStrategy.WholeHistory</code> – compress entire history into a summary.</li>



<li><code>HistoryCompressionStrategy.FromLastNMessages(100)</code> – only compress the last N messages.</li>



<li><code>HistoryCompressionStrategy.Chunked(20)</code> – compress in chunks of N messages.</li>



<li><code data-enlighter-language="java" class="EnlighterJSRAW">RetrieveFactsFromHistory</code> – extract specific facts from history (e.g. &#8220;What&#8217;s the user&#8217;s name?&#8221; or &#8220;Which operations were performed?&#8221;).</li>
</ul>



<p>You can also implement your own history compression strategy.</p>



<h3 class="wp-block-heading"><strong>Managing Java threads</strong></h3>



<p>In a typical Java application, you want fine-grained control over thread pools. Maybe you have a dedicated pool for CPU-bound work and another for I/O operations. Koog lets you specify a separate <code>ExecutorService</code> for each part of an agent’s execution:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="java" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">var threadControlledAgent = AIAgent.builder()
    .promptExecutor(promptExecutor)
    .agentConfig(AIAgentConfig.builder(OpenAIModels.Chat.GPT5_2)
        .strategyExecutorService(mainExecutorService)      // For agent logic
        .llmRequestExecutorService(ioExecutorService)      // For LLM API calls
        .build())
    .build();</pre>



<p>This separation lets you optimize resource usage – for example, using a larger pool for I/O-bound LLM requests while keeping a smaller pool for strategy execution logic.</p>



<h3 class="wp-block-heading"><strong>Try Koog for Java</strong></h3>



<p>Koog for Java brings enterprise-grade agent engineering to your Java applications with an API that feels natural and idiomatic. Whether you&#8217;re building simple tool-calling agents or complex multi-step workflows with persistence and observability, Koog provides the abstractions you need.</p>



<p>Get started here: <a href="https://docs.koog.ai/" target="_blank" rel="noreferrer noopener">https://docs.koog.ai/</a></p>
]]></content:encoded>
					
		
		
		                    <language>
                        <code><![CDATA[zh-hans]]></code>
                        <url>https://blog.jetbrains.com/zh-hans/ai/2026/03/koog-comes-to-java/</url>
                    </language>
                	</item>
		<item>
		<title>Sunsetting Code With Me</title>
		<link>https://blog.jetbrains.com/platform/2026/03/sunsetting-code-with-me/</link>
		
		<dc:creator><![CDATA[Ekaterina Ryabukha]]></dc:creator>
		<pubDate>Mon, 16 Mar 2026 08:51:40 +0000</pubDate>
		<featuredImage>https://blog.jetbrains.com/wp-content/uploads/2026/03/IDEs-social-BlogFeatured-1280x720-1.png</featuredImage>		<product ><![CDATA[idea]]></product>
		<category><![CDATA[news]]></category>
		<category><![CDATA[codewithme]]></category>
		<guid isPermaLink="false">https://blog.jetbrains.com/?post_type=platform&#038;p=684892</guid>

					<description><![CDATA[Code With Me has been part of JetBrains IDEs for years, providing real-time collaborative coding and pair programming directly inside your development environment. It enabled teams to share a workspace, tackle issues together, and learn from one another without leaving the IDE. Today, we’re announcing plans to gradually sunset Code With Me. In this post, [&#8230;]]]></description>
										<content:encoded><![CDATA[
<p><a href="https://blog.jetbrains.com/blog/2020/09/28/code-with-me-eap/">Code With Me</a> has been part of JetBrains IDEs for years, providing real-time collaborative coding and pair programming directly inside your development environment. It enabled teams to share a workspace, tackle issues together, and learn from one another without leaving the IDE.</p>



<p>Today, we’re announcing plans to gradually sunset Code With Me.</p>



<p>In this post, we’ll explain why we’re making this change, what the sunset timeline looks like, and what it means for existing users. We’ll also outline how the transition will work and answer common questions in the <a href="#faq">FAQ below</a> to help make the process as smooth as possible.</p>



<h2 class="wp-block-heading">Why we’re making this change</h2>



<p>Demand for built-in pair programming and real-time collaboration tools like Code With Me peaked during the pandemic and has since shifted, with many teams adopting different collaboration workflows. At the same time, maintaining Code With Me alongside the evolving IntelliJ Platform requires ongoing engineering investment.</p>



<p>After reviewing usage trends and the long-term direction of our IDEs, we’ve decided to discontinue Code With Me. This will allow us to focus our efforts on areas that deliver the most value to developers and align with how teams collaborate today.</p>



<h2 class="wp-block-heading">Timeline and what to expect</h2>



<p><strong>2026.1 release</strong></p>



<ul>
<li>Code With Me will be <strong>unbundled</strong> from all JetBrains IDEs and made available as a <a href="https://plugins.jetbrains.com/plugin/14896-code-with-me" target="_blank" rel="noopener">separate plugin</a> via JetBrains Marketplace.</li>



<li>2026.1 will be the <strong>last IDE release to officially support Code With Me</strong>.</li>



<li>No new features will be developed from this point forward.</li>
</ul>



<p><strong>Transition period (2026.1 → Q1 2027)</strong></p>



<ul>
<li>The plugin will continue to function on supported IDE versions.</li>



<li><strong>Security updates</strong> will be provided during this period.</li>



<li>Public relay infrastructure will remain operational.</li>
</ul>



<p><strong>Final shutdown (Q1 2027)</strong></p>



<ul>
<li>The public relay infrastructure will be turned off.</li>



<li>The service will be fully deactivated.</li>
</ul>



<h2 class="wp-block-heading">What this means for existing Code With Me users</h2>



<p>We understand that Code With Me is part of some teams’ workflows, and we want to make this transition as smooth as possible.&nbsp;</p>



<p>If you currently use Code With Me:</p>



<ul>
<li>You can continue installing and using the plugin from JetBrains Marketplace throughout the transition period outlined above.</li>



<li>It will work on supported IDE versions, with security updates provided until the final sunset date in Q1 2027.</li>



<li>Existing<strong> subscriptions will remain active</strong> until support ends. New sales and renewals will be discontinued.</li>



<li>Our Support team will remain available during the transition to assist with any questions or compatibility concerns.</li>
</ul>



<p>Depending on your workflow, you may find that general-purpose collaboration tools cover your needs. If your primary use case is remote access to development environments, <a href="https://www.jetbrains.com/remote-development/" target="_blank" rel="noopener">our remote development features</a>, which have been improved significantly in recent releases, may be a better fit.</p>



<p>For more details, see the FAQ below. If you have questions or feedback, please leave a comment or <a href="https://www.jetbrains.com/support/" data-type="link" data-id="https://www.jetbrains.com/support/" target="_blank" rel="noopener">contact our Support team</a>.</p>



<h2 class="wp-block-heading">Looking ahead</h2>



<p>As we invest in the future of our tools, we remain focused on delivering tools that support modern software development and bring the greatest value to developers and teams.</p>



<p>We’re grateful to everyone who used Code With Me, shared feedback, and contributed to its journey. Your input has helped shape the product. Thank you!</p>



<p><em>The JetBrains team</em></p>



<h2 class="wp-block-heading">FAQ</h2>



<p>Below, we have compiled answers to the most common questions about the discontinuation of Code With Me and the migration options available.</p>



<h3 class="wp-block-heading">What is the last IDE release to support Code With Me?</h3>



<p>2026.1 will be the last IDE release to officially support Code With Me.</p>



<h3 class="wp-block-heading">Will I still be able to use Code With Me after the 2026.1 release?</h3>



<p>Yes, you will be able to use Code With Me on all supported IDE versions for at least one year until Q1 2027. After that, our public relays will be shut down, and public sessions won’t be available anymore.</p>



<h3 class="wp-block-heading">What alternatives are available for Code With Me users?</h3>



<p>Depending on your workflow, you may find that general-purpose collaboration tools cover your needs. If your primary use case is remote access to development environments, <a href="https://www.jetbrains.com/remote-development/" target="_blank" rel="noopener">our remote development features</a> may be a better fit.</p>



<h3 class="wp-block-heading">Does this decision affect remote development within JetBrains IDEs?</h3>



<p>No. The discontinuation of Code With Me does not affect JetBrains IDEs’ remote development functionality.</p>



<p>We continue to actively invest in and evolve our remote development capabilities as part of the IntelliJ Platform. Remote development remains a strategic focus area, and progress in this direction will continue.</p>



<h3 class="wp-block-heading">What will happen to my Code With Me license?</h3>



<p>You can continue using Code With Me on supported IDE versions until the end of your current subscription term. Code With Me subscriptions will not renew.</p>



<p>For more details about your specific subscription, please contact our Support team.</p>



<h3 class="wp-block-heading">I’m using Code With Me Enterprise. What does this mean for me?</h3>



<p>If you are using Code With Me as part of a JetBrains IDE Services (Enterprise) agreement, your current contract terms remain valid during the supported period.</p>



<p>As we approach the end of the sunset period, renewal of Code With Me Enterprise will no longer be available. For contracts with specific provisions or custom arrangements, we will work individually to define the appropriate transition path.</p>



<p>If you have questions about how this change affects your agreement, please contact your JetBrains representative.</p>



<h3 class="wp-block-heading">What should I do if I recently purchased an Code With Me license?</h3>



<p><a href="https://sales.jetbrains.com/hc/en-gb/articles/115000913704-How-can-I-get-a-refund" target="_blank" rel="noopener">Our standard refund policy</a> applies to recent purchases. If you have questions about your eligibility for a refund, please contact JetBrains support.</p>



<h3 class="wp-block-heading">Where can I find more information or assistance?</h3>



<p>For any further questions or support inquiries, please visit our <a href="https://www.jetbrains.com/support" target="_blank" rel="noopener">Support page</a> or reach out to us directly. We sincerely appreciate the Code With Me community&#8217;s support and look forward to continuing to provide the best solutions within our JetBrains IDEs.</p>
]]></content:encoded>
					
		
		
		                    <language>
                        <code><![CDATA[zh-hans]]></code>
                        <url>https://blog.jetbrains.com/zh-hans/platform/2026/03/sunsetting-code-with-me/</url>
                    </language>
                	</item>
	</channel>
</rss>
