<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Karan Sahani</title>
    <description>The latest articles on Forem by Karan Sahani (@karansahani78).</description>
    <link>https://forem.com/karansahani78</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3882361%2Fd9c33505-6eb9-4ecf-ba39-25e4aa109bda.jpeg</url>
      <title>Forem: Karan Sahani</title>
      <link>https://forem.com/karansahani78</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/karansahani78"/>
    <language>en</language>
    <item>
      <title>Spring Boot CRUD Generator v1.1.0 — JPA Relationships, Done Right</title>
      <dc:creator>Karan Sahani</dc:creator>
      <pubDate>Sat, 25 Apr 2026 13:36:28 +0000</pubDate>
      <link>https://forem.com/karansahani78/spring-boot-crud-generator-v110-jpa-relationships-done-right-2cb</link>
      <guid>https://forem.com/karansahani78/spring-boot-crud-generator-v110-jpa-relationships-done-right-2cb</guid>
      <description>&lt;p&gt;🔗 Plugin link: &lt;a href="https://plugins.jetbrains.com/plugin/29476-spring-boot-crud-generator" rel="noopener noreferrer"&gt;https://plugins.jetbrains.com/plugin/29476-spring-boot-crud-generator&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I shipped an update to my IntelliJ plugin that fixes something subtle but critical — the way generated Spring Boot code handles JPA relationships.&lt;/p&gt;

&lt;p&gt;The plugin has crossed &lt;strong&gt;1200+ downloads&lt;/strong&gt;, and the feedback pattern was clear:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Everything works fine… until you add relationships.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  ❌ The Real Problems
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. LazyInitializationException at runtime
&lt;/h3&gt;

&lt;p&gt;Generated mappers were doing this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="n"&gt;entity&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getPosts&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;stream&lt;/span&gt;&lt;span class="o"&gt;()...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Works in tests.&lt;br&gt;
Breaks in production (outside transaction scope).&lt;/p&gt;


&lt;h3&gt;
  
  
  2. null IDs in API responses
&lt;/h3&gt;

&lt;p&gt;DTO generator was skipping &lt;code&gt;id&lt;/code&gt; completely.&lt;/p&gt;

&lt;p&gt;So every response looked like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"java"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Which makes your API… basically unusable.&lt;/p&gt;




&lt;h3&gt;
  
  
  3. Mapper calling setters that didn’t exist
&lt;/h3&gt;

&lt;p&gt;Inverse &lt;code&gt;@OneToMany&lt;/code&gt; relationships were not generated in DTOs.&lt;/p&gt;

&lt;p&gt;Result:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Mapper tries → &lt;code&gt;dto.setPostIds(...)&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;DTO doesn’t have it → ❌ compile error&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  ✅ What v1.1.0 Fixes
&lt;/h2&gt;

&lt;h3&gt;
  
  
  ✔ ID is always present
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Included in DTO&lt;/li&gt;
&lt;li&gt;No &lt;code&gt;@NotNull&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Marked as &lt;code&gt;NOT_REQUIRED&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Server-controlled&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  ✔ Safe toDto() mapping
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="n"&gt;dto&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setId&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;entity&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getId&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;First line. Always.&lt;/p&gt;




&lt;h3&gt;
  
  
  ✔ Collections → null (intentional)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="n"&gt;dto&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setPostIds&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Why?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;null&lt;/code&gt; = not loaded&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;emptyList()&lt;/code&gt; = loaded but empty ❌ misleading&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Also avoids LazyInitializationException entirely.&lt;/p&gt;




&lt;h3&gt;
  
  
  ✔ Single relationships → ID only
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="n"&gt;dto&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setUserId&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;entity&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getUser&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;getId&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No nested objects.&lt;br&gt;
No recursion.&lt;br&gt;
Frontend-friendly.&lt;/p&gt;


&lt;h3&gt;
  
  
  ✔ Import system fixed
&lt;/h3&gt;

&lt;p&gt;No more garbage like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="n"&gt;com&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;entity&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;entity&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;User&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  🧠 Design Philosophy
&lt;/h2&gt;

&lt;p&gt;Most generators try to map everything.&lt;/p&gt;

&lt;p&gt;That’s the root problem.&lt;/p&gt;

&lt;p&gt;This update follows a stricter rule:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Don’t trigger database access in mappers&lt;/li&gt;
&lt;li&gt;Don’t assume relationships are loaded&lt;/li&gt;
&lt;li&gt;Don’t generate code that only works in demos&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  🎯 Result
&lt;/h2&gt;

&lt;p&gt;You get:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Predictable API responses&lt;/li&gt;
&lt;li&gt;No lazy loading crashes&lt;/li&gt;
&lt;li&gt;DTOs that always match mappers&lt;/li&gt;
&lt;li&gt;Code that actually survives real projects&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  🙌 Final Thought
&lt;/h2&gt;

&lt;p&gt;This isn’t a flashy release.&lt;/p&gt;

&lt;p&gt;It’s a &lt;strong&gt;correctness upgrade&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The kind that saves hours of debugging later.&lt;/p&gt;




&lt;p&gt;If you’re already using the plugin — update it.&lt;/p&gt;

&lt;p&gt;If not — now it’s finally safe to use in real-world projects.&lt;/p&gt;

&lt;p&gt;Would love feedback 👇&lt;/p&gt;

</description>
      <category>java</category>
      <category>showdev</category>
      <category>springboot</category>
      <category>tooling</category>
    </item>
    <item>
      <title>⚡ I Got Tired of Writing the Same Spring Boot Code… So I Built a Generator Inside IntelliJ</title>
      <dc:creator>Karan Sahani</dc:creator>
      <pubDate>Thu, 16 Apr 2026 11:35:20 +0000</pubDate>
      <link>https://forem.com/karansahani78/i-got-tired-of-writing-the-same-spring-boot-code-so-i-built-a-generator-inside-intellij-g48</link>
      <guid>https://forem.com/karansahani78/i-got-tired-of-writing-the-same-spring-boot-code-so-i-built-a-generator-inside-intellij-g48</guid>
      <description>&lt;h1&gt;
  
  
  ⚡ I Got Tired of Writing the Same Spring Boot Code… So I Built a Generator Inside IntelliJ
&lt;/h1&gt;

&lt;p&gt;Every Spring Boot project starts the same way.&lt;/p&gt;

&lt;p&gt;You create an entity…&lt;br&gt;
and then spend the next hour writing:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Repository&lt;/li&gt;
&lt;li&gt;Service&lt;/li&gt;
&lt;li&gt;Controller&lt;/li&gt;
&lt;li&gt;DTOs&lt;/li&gt;
&lt;li&gt;Mappers&lt;/li&gt;
&lt;li&gt;Exception handling&lt;/li&gt;
&lt;li&gt;Pagination&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Nothing difficult.&lt;br&gt;
Just repetitive.&lt;/p&gt;

&lt;p&gt;And repetition is where productivity dies.&lt;/p&gt;

&lt;h2&gt;
  
  
  🤯 The Real Problem Nobody Talks About
&lt;/h2&gt;

&lt;p&gt;It’s not about writing code.&lt;/p&gt;

&lt;p&gt;It’s about rewriting the &lt;em&gt;same code&lt;/em&gt; again and again:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Same patterns&lt;/li&gt;
&lt;li&gt;Same structure&lt;/li&gt;
&lt;li&gt;Same logic&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And yet…&lt;/p&gt;

&lt;p&gt;We still do it manually.&lt;/p&gt;




&lt;h2&gt;
  
  
  🧠 The Idea
&lt;/h2&gt;

&lt;p&gt;I asked myself a simple question:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;What if selecting a class could generate an entire backend layer?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Not boilerplate.&lt;br&gt;
Not templates.&lt;/p&gt;

&lt;p&gt;But &lt;strong&gt;production-ready code&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  ⚙️ Under the Hood (The Interesting Part)
&lt;/h2&gt;

&lt;p&gt;Building this inside IntelliJ was way more complex than expected.&lt;/p&gt;

&lt;h3&gt;
  
  
  🔹 1. Reading Code Like IntelliJ Does (PSI)
&lt;/h3&gt;

&lt;p&gt;You don’t parse Java files manually.&lt;/p&gt;

&lt;p&gt;You work with IntelliJ’s &lt;strong&gt;PSI (Program Structure Interface)&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Detect fields&lt;/li&gt;
&lt;li&gt;Identify annotations like &lt;code&gt;@Entity&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Extract metadata&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Without PSI → nothing works.&lt;/p&gt;




&lt;h3&gt;
  
  
  🔹 2. Generating Code That Doesn’t Look Generated
&lt;/h3&gt;

&lt;p&gt;Most generators fail here.&lt;/p&gt;

&lt;p&gt;They produce:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Ugly code&lt;/li&gt;
&lt;li&gt;Poor structure&lt;/li&gt;
&lt;li&gt;Hard to maintain&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I wanted the opposite:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Code that feels like a senior developer wrote it.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That meant:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Clean layering (Controller → Service → Repository)&lt;/li&gt;
&lt;li&gt;DTO separation&lt;/li&gt;
&lt;li&gt;Proper naming conventions&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  🔹 3. Dependency Injection Without Breaking Projects
&lt;/h3&gt;

&lt;p&gt;This turned out to be one of the hardest parts.&lt;/p&gt;

&lt;p&gt;You need to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Detect if dependency already exists&lt;/li&gt;
&lt;li&gt;Support both Maven &amp;amp; Gradle&lt;/li&gt;
&lt;li&gt;Avoid duplicates&lt;/li&gt;
&lt;li&gt;Insert safely inside correct block&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A naive approach breaks builds instantly.&lt;/p&gt;

&lt;p&gt;So I built logic to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Scan existing dependencies&lt;/li&gt;
&lt;li&gt;Inject only when missing&lt;/li&gt;
&lt;li&gt;Keep it idempotent&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  🔹 4. Optional Security (JWT)
&lt;/h3&gt;

&lt;p&gt;Security isn’t just “add dependency”.&lt;/p&gt;

&lt;p&gt;It involves:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Filters&lt;/li&gt;
&lt;li&gt;Authentication flow&lt;/li&gt;
&lt;li&gt;User + roles&lt;/li&gt;
&lt;li&gt;Token handling&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And it had to be:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Optional. Clean. Non-breaking.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h3&gt;
  
  
  🔹 5. Supporting Multiple Databases
&lt;/h3&gt;

&lt;p&gt;Different teams → different databases.&lt;/p&gt;

&lt;p&gt;So I added dynamic support for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;MySQL&lt;/li&gt;
&lt;li&gt;PostgreSQL&lt;/li&gt;
&lt;li&gt;MongoDB&lt;/li&gt;
&lt;li&gt;H2&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Challenge:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;JPA vs Mongo are fundamentally different&lt;/li&gt;
&lt;li&gt;Configurations vary&lt;/li&gt;
&lt;li&gt;Drivers must be injected conditionally&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  ⚡ The Biggest Lesson
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;Generating code is easy.&lt;br&gt;
Generating &lt;strong&gt;safe, usable, production-ready code&lt;/strong&gt; is hard.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  🧩 What This Changed for Me
&lt;/h2&gt;

&lt;p&gt;I stopped thinking like a developer writing code.&lt;/p&gt;

&lt;p&gt;And started thinking like:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A developer building tools for developers.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  🚀 Why This Matters
&lt;/h2&gt;

&lt;p&gt;This isn’t just about saving time.&lt;/p&gt;

&lt;p&gt;It’s about:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Reducing friction&lt;/li&gt;
&lt;li&gt;Standardizing architecture&lt;/li&gt;
&lt;li&gt;Eliminating repetitive mental load&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Because energy should go into solving real problems…&lt;br&gt;
not rewriting CRUD for the 50th time.&lt;/p&gt;

&lt;h2&gt;
  
  
  💬 Final Thought
&lt;/h2&gt;

&lt;p&gt;The best tools don’t just automate tasks.&lt;/p&gt;

&lt;p&gt;They remove &lt;em&gt;unnecessary thinking&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;If you’ve ever tried building developer tools,&lt;br&gt;
or struggled with safe code generation…&lt;/p&gt;

&lt;p&gt;I’d love to hear your approach 👇&lt;/p&gt;

</description>
      <category>automation</category>
      <category>productivity</category>
      <category>showdev</category>
      <category>springboot</category>
    </item>
  </channel>
</rss>
