<?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: Marko</title>
    <description>The latest articles on Forem by Marko (@mzivkovicdev).</description>
    <link>https://forem.com/mzivkovicdev</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%2F3728756%2F86f755a6-9bcf-479e-8894-b5a22bee05e4.png</url>
      <title>Forem: Marko</title>
      <link>https://forem.com/mzivkovicdev</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/mzivkovicdev"/>
    <language>en</language>
    <item>
      <title>Why Small, Regular Releases Matter in Open Source</title>
      <dc:creator>Marko</dc:creator>
      <pubDate>Wed, 25 Mar 2026 13:34:24 +0000</pubDate>
      <link>https://forem.com/mzivkovicdev/why-small-regular-releases-matter-in-open-source-4nkd</link>
      <guid>https://forem.com/mzivkovicdev/why-small-regular-releases-matter-in-open-source-4nkd</guid>
      <description>&lt;p&gt;When people talk about open source progress, they often focus on big features.&lt;/p&gt;

&lt;p&gt;A major redesign.&lt;br&gt;&lt;br&gt;
A long-awaited capability.&lt;br&gt;&lt;br&gt;
A release packed with changes.&lt;/p&gt;

&lt;p&gt;That kind of release can feel exciting.&lt;/p&gt;

&lt;p&gt;But in practice, many open source projects become healthier not because of huge releases, but because of &lt;strong&gt;small, regular ones&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;After working on my own tooling projects, I have started to appreciate that steady release cadence is not just a delivery habit. It is part of how trust is built around an open source project.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Large releases create more friction than people expect
&lt;/h2&gt;

&lt;p&gt;A big release may sound productive, but it often comes with hidden cost:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;more things to test&lt;/li&gt;
&lt;li&gt;more things to explain&lt;/li&gt;
&lt;li&gt;more chances for regressions&lt;/li&gt;
&lt;li&gt;more complicated release notes&lt;/li&gt;
&lt;li&gt;more uncertainty for users&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When too many changes are bundled together, it becomes harder for users to understand what actually improved.&lt;/p&gt;

&lt;p&gt;Instead of:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“Nice, I can adopt this one improvement right away”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;the reaction becomes:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“This looks substantial, I will check it later”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;And “later” often means never.&lt;/p&gt;

&lt;p&gt;Smaller releases reduce that friction.&lt;br&gt;&lt;br&gt;
They make progress easier to consume.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Regular releases make a project feel alive
&lt;/h2&gt;

&lt;p&gt;One of the silent questions people ask when they discover an open source project is:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“Is this actually maintained?”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;They may not ask it directly, but they absolutely evaluate it.&lt;/p&gt;

&lt;p&gt;Regular releases answer that question better than promises do.&lt;/p&gt;

&lt;p&gt;A project with clear, incremental releases signals a few important things:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the maintainer is actively working on it&lt;/li&gt;
&lt;li&gt;improvements are being shipped, not just discussed&lt;/li&gt;
&lt;li&gt;bugs are getting fixed&lt;/li&gt;
&lt;li&gt;feedback can turn into actual releases&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That creates confidence.&lt;/p&gt;

&lt;p&gt;Even if a release is not huge, it still tells users:&lt;br&gt;&lt;br&gt;
this project is moving.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Small releases improve feedback loops
&lt;/h2&gt;

&lt;p&gt;This is especially important for tools, libraries, generators, and frameworks.&lt;/p&gt;

&lt;p&gt;If you wait too long and pack many changes into one release, feedback becomes blurry.&lt;br&gt;&lt;br&gt;
When users react, it is harder to know what helped, what confused them, and what introduced problems.&lt;/p&gt;

&lt;p&gt;Smaller releases make feedback much more useful.&lt;/p&gt;

&lt;p&gt;You add one meaningful feature.&lt;br&gt;&lt;br&gt;
You fix one real bug.&lt;br&gt;&lt;br&gt;
You improve one part of the docs.&lt;br&gt;&lt;br&gt;
You clean up one internal area.&lt;/p&gt;

&lt;p&gt;That gives users something concrete to evaluate.&lt;/p&gt;

&lt;p&gt;It also gives maintainers a much cleaner path for iteration.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Not every valuable release needs a flashy headline
&lt;/h2&gt;

&lt;p&gt;This is something I have come to appreciate more over time.&lt;/p&gt;

&lt;p&gt;Some releases are exciting because they introduce a visible feature.&lt;br&gt;&lt;br&gt;
Others are valuable because they improve reliability, clarity, or maintainability.&lt;/p&gt;

&lt;p&gt;Those quieter improvements matter a lot:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;better docs&lt;/li&gt;
&lt;li&gt;better examples&lt;/li&gt;
&lt;li&gt;safer defaults&lt;/li&gt;
&lt;li&gt;less fragile internal code&lt;/li&gt;
&lt;li&gt;a bug fix that removes edge-case failures&lt;/li&gt;
&lt;li&gt;small quality-of-life improvements for generated output or APIs&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These are not always “headline features,” but they are often exactly what makes a project more usable.&lt;/p&gt;

&lt;p&gt;A healthy open source project should not wait for a dramatic update before shipping progress.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Smaller scope makes release notes better too
&lt;/h2&gt;

&lt;p&gt;Release notes are part of the product experience.&lt;/p&gt;

&lt;p&gt;If a release is too broad, the notes become harder to write and harder to read.&lt;br&gt;&lt;br&gt;
Everything starts sounding equally important.&lt;/p&gt;

&lt;p&gt;But when a release is focused, the value is easier to communicate:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;here is the feature&lt;/li&gt;
&lt;li&gt;here is the bug fix&lt;/li&gt;
&lt;li&gt;here is the doc improvement&lt;/li&gt;
&lt;li&gt;here is the internal cleanup&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That kind of clarity helps both maintainers and users.&lt;/p&gt;

&lt;p&gt;A good release note should make someone think:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“I understand what changed, and I know why it matters.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Smaller releases make that easier.&lt;/p&gt;

&lt;h2&gt;
  
  
  6. Shipping regularly builds momentum
&lt;/h2&gt;

&lt;p&gt;This might be the most underrated part.&lt;/p&gt;

&lt;p&gt;Open source projects often lose energy when maintainers feel like every release has to be “big enough.”&lt;/p&gt;

&lt;p&gt;That creates pressure.&lt;br&gt;&lt;br&gt;
And pressure creates delay.&lt;/p&gt;

&lt;p&gt;But when smaller releases are acceptable, momentum becomes easier to maintain.&lt;/p&gt;

&lt;p&gt;You do not need to wait until 12 things are finished.&lt;br&gt;&lt;br&gt;
You can ship 3 or 4 useful changes, document them well, and move forward.&lt;/p&gt;

&lt;p&gt;That keeps the project active.&lt;br&gt;&lt;br&gt;
It keeps the feedback loop alive.&lt;br&gt;&lt;br&gt;
And it makes the next release easier too.&lt;/p&gt;

&lt;h2&gt;
  
  
  Final thought
&lt;/h2&gt;

&lt;p&gt;In open source, consistency is often more valuable than size.&lt;/p&gt;

&lt;p&gt;A project that releases useful improvements regularly tends to feel more trustworthy than one that disappears for long periods and returns with an oversized release.&lt;/p&gt;

&lt;p&gt;Small releases are easier to understand, easier to test, easier to communicate, and easier to build on.&lt;/p&gt;

&lt;p&gt;That is the approach I try to follow in my own work.&lt;/p&gt;

&lt;p&gt;For example, I recently released &lt;strong&gt;v1.7.0&lt;/strong&gt; of &lt;strong&gt;Spring CRUD Generator&lt;/strong&gt;. It is a focused release: better OpenAPI generation through field examples, bulk POST support, extra documentation, a bug fix around relation handling, and a small internal refactor.&lt;/p&gt;

&lt;p&gt;That is not a huge release by design.&lt;/p&gt;

&lt;p&gt;I would rather ship useful progress regularly than wait too long and bundle everything into something harder to maintain, explain, and trust.&lt;/p&gt;

&lt;p&gt;If you want to take a look:&lt;br&gt;&lt;br&gt;
&lt;code&gt;https://github.com/mzivkovicdev/spring-crud-generator&lt;/code&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>opensource</category>
      <category>springboot</category>
      <category>programming</category>
    </item>
    <item>
      <title>What Makes a CRUD Generator Actually Usable?</title>
      <dc:creator>Marko</dc:creator>
      <pubDate>Thu, 19 Mar 2026 14:34:49 +0000</pubDate>
      <link>https://forem.com/mzivkovicdev/what-makes-a-crud-generator-actually-usable-26cc</link>
      <guid>https://forem.com/mzivkovicdev/what-makes-a-crud-generator-actually-usable-26cc</guid>
      <description>&lt;p&gt;There are many code generators that can create CRUD resources from a config file.&lt;/p&gt;

&lt;p&gt;On paper, that sounds great.&lt;/p&gt;

&lt;p&gt;In practice, the real question is not:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“Can it generate code?”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The real question is:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“Can I actually trust the generated project enough to use it?”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That is where many generators start to fall apart.&lt;/p&gt;

&lt;p&gt;Generating a few entities, repositories, and controllers is the easy part. The harder part is making the generated result feel reliable, understandable, and usable in a real workflow.&lt;/p&gt;

&lt;p&gt;After working on my own Spring Boot CRUD generator, I realized that usability does not come from generation alone. It comes from all the small things around the generation that reduce friction and increase trust.&lt;/p&gt;

&lt;p&gt;Here are a few lessons that stand out.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Code generation is not enough
&lt;/h2&gt;

&lt;p&gt;A generator can create a lot of files and still feel incomplete.&lt;/p&gt;

&lt;p&gt;You can generate entities, services, controllers, mappers, tests, migrations, and configuration files, and the first impression may still be:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“Okay, but will this actually work in my project?”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That hesitation is normal.&lt;/p&gt;

&lt;p&gt;Developers do not trust generated code just because it exists. They trust it when they can see that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the input format is clear&lt;/li&gt;
&lt;li&gt;the output is predictable&lt;/li&gt;
&lt;li&gt;the generated application can actually run&lt;/li&gt;
&lt;li&gt;the project will not break because of missing setup&lt;/li&gt;
&lt;li&gt;the API surface behaves the way they expect&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A useful generator is not just a code emitter.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Validation matters more than people think
&lt;/h2&gt;

&lt;p&gt;A spec-driven generator lives or dies by the quality of its validation.&lt;/p&gt;

&lt;p&gt;If a spec file is invalid, users should know &lt;strong&gt;&lt;em&gt;before&lt;/em&gt;&lt;/strong&gt; generation.&lt;br&gt;
If the spec is incomplete, they should know &lt;strong&gt;&lt;em&gt;before&lt;/em&gt;&lt;/strong&gt; generation.&lt;br&gt;
If the target project setup is missing required dependencies, they should know &lt;strong&gt;&lt;em&gt;before&lt;/em&gt;&lt;/strong&gt; generation.&lt;/p&gt;

&lt;p&gt;That is why dry-run validation is so valuable.&lt;/p&gt;

&lt;p&gt;A dry run gives the user a chance to validate the spec and project setup without committing to a full generation step. It turns generation into a safer workflow:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;write or update the CRUD spec&lt;/li&gt;
&lt;li&gt;run validation&lt;/li&gt;
&lt;li&gt;fix issues early&lt;/li&gt;
&lt;li&gt;generate resources only when the setup is correct&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;That one layer of feedback makes a generator feel much more professional.&lt;/p&gt;
&lt;h2&gt;
  
  
  3. Dependency checks are part of usability
&lt;/h2&gt;

&lt;p&gt;This is one of those features that is not flashy, but it solves a real pain.&lt;/p&gt;

&lt;p&gt;A generator may support optional features like GraphQL, caching, OpenAPI, Docker integration, or workflow generation. But if the target project is missing required dependencies, the user often discovers that only after compilation fails.&lt;/p&gt;

&lt;p&gt;That is a bad experience.&lt;/p&gt;

&lt;p&gt;A dependency check in the validation step gives immediate feedback:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;your spec enables X&lt;/li&gt;
&lt;li&gt;your project is missing Y&lt;/li&gt;
&lt;li&gt;fix that first&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is not a “marketing feature,” but it is exactly the kind of thing that makes a tool feel mature.&lt;/p&gt;
&lt;h2&gt;
  
  
  4. Sorting is a small feature with big practical value
&lt;/h2&gt;

&lt;p&gt;If a tool generates list endpoints, sorting quickly becomes one of those things users expect by default.&lt;/p&gt;

&lt;p&gt;Basic CRUD is rarely enough on its own.&lt;/p&gt;

&lt;p&gt;Even a very simple generated API becomes much more useful if it supports controlled sorting like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;sort by &lt;code&gt;name&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;sort by &lt;code&gt;price&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;sort by &lt;code&gt;releaseDate&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The important part is not just &lt;strong&gt;&lt;em&gt;adding&lt;/em&gt;&lt;/strong&gt; sorting, but adding it in a controlled way.&lt;/p&gt;

&lt;p&gt;A good generator should not blindly allow sorting by anything. It should let the user explicitly define which fields are sortable. That gives a better balance between flexibility and predictability.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;sort&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;allowedFields&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;price&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;releaseDate&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
  &lt;span class="na"&gt;defaultDirection&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ASC&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This kind of design keeps the spec simple while still making the generated API more realistic.&lt;/p&gt;

&lt;p&gt;Sorting may not sound like a major release feature, but it makes generated CRUD resources feel much closer to something you would actually expose and use.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Documentation is not just documentation
&lt;/h2&gt;

&lt;p&gt;Good documentation does more than explain features.&lt;/p&gt;

&lt;p&gt;It answers silent questions like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What does this tool actually generate?&lt;/li&gt;
&lt;li&gt;How much setup is required?&lt;/li&gt;
&lt;li&gt;What does the generated result look like?&lt;/li&gt;
&lt;li&gt;Can I trust the output?&lt;/li&gt;
&lt;li&gt;Is this maintained?&lt;/li&gt;
&lt;li&gt;Is there a concrete example I can follow?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A README is not just a description. It is part of the product.&lt;/p&gt;

&lt;p&gt;A clearer README reduces confusion, shortens onboarding time, and makes it easier for users to move from curiosity to actual usage.&lt;/p&gt;

&lt;p&gt;That is especially important for generators, because they involve a bigger trust jump than a typical library.&lt;/p&gt;

&lt;p&gt;With a normal library, a developer adds one dependency and tries one API.&lt;/p&gt;

&lt;p&gt;With a generator, they are letting a tool create part of their codebase.&lt;/p&gt;

&lt;p&gt;That requires more confidence.&lt;/p&gt;

&lt;h2&gt;
  
  
  6. A demo video changes how people evaluate the project
&lt;/h2&gt;

&lt;p&gt;This may be the most underrated part.&lt;/p&gt;

&lt;p&gt;Developers believe much faster when they can &lt;strong&gt;&lt;em&gt;see&lt;/em&gt;&lt;/strong&gt; the flow.&lt;/p&gt;

&lt;p&gt;A short demo video can answer in under a minute what a long README sometimes cannot fully communicate:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;here is the CRUD spec&lt;/li&gt;
&lt;li&gt;here is the generation step&lt;/li&gt;
&lt;li&gt;here is the generated project&lt;/li&gt;
&lt;li&gt;here is the app running&lt;/li&gt;
&lt;li&gt;here are the API calls working&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That does two things at once:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;it proves that the tool works&lt;/li&gt;
&lt;li&gt;it makes the project feel real&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For generator-style tools, that visual proof matters a lot.&lt;/p&gt;

&lt;p&gt;People do not just want to see source code. They want to see the end-to-end path from input to working result.&lt;/p&gt;

&lt;p&gt;In many cases, a demo video is not “extra content.”&lt;br&gt;
It is part of trust-building.&lt;/p&gt;

&lt;h2&gt;
  
  
  7. The best improvements are often not the loudest ones
&lt;/h2&gt;

&lt;p&gt;Not every useful release looks impressive in a headline.&lt;/p&gt;

&lt;p&gt;Some improvements are exciting and obvious.&lt;br&gt;
Others are quieter, but they make the product much better:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;better validation&lt;/li&gt;
&lt;li&gt;better docs&lt;/li&gt;
&lt;li&gt;better defaults&lt;/li&gt;
&lt;li&gt;safer generation flow&lt;/li&gt;
&lt;li&gt;fewer compile-time surprises&lt;/li&gt;
&lt;li&gt;more realistic generated endpoints&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These things may not always look like major product announcements, but they are often what move a project from “interesting” to “actually usable.”&lt;/p&gt;

&lt;p&gt;That distinction matters.&lt;/p&gt;

&lt;p&gt;Because many tools can generate code.&lt;/p&gt;

&lt;p&gt;Far fewer tools make the full workflow feel safe, clear, and dependable.&lt;/p&gt;

&lt;h2&gt;
  
  
  Final thought
&lt;/h2&gt;

&lt;p&gt;If you are building a generator, think beyond output quantity.&lt;/p&gt;

&lt;p&gt;Do not focus only on how many files you can generate.&lt;/p&gt;

&lt;p&gt;Focus on things like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;how easy it is to validate input&lt;/li&gt;
&lt;li&gt;how safe it is to run generation&lt;/li&gt;
&lt;li&gt;how realistic the generated result is&lt;/li&gt;
&lt;li&gt;how quickly a new user can trust what they are seeing&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That is where usability really comes from.&lt;/p&gt;

&lt;p&gt;I recently pushed a new release of my own project, &lt;strong&gt;Spring CRUD Generator&lt;/strong&gt;, with exactly that mindset in mind: improving validation, adding dependency checks, introducing entity-level sorting, cleaning up the README, and adding a demo video plus the demo CRUD spec used in that video.&lt;/p&gt;

&lt;p&gt;Repository: &lt;a href="https://github.com/mzivkovicdev/spring-crud-generator" rel="noopener noreferrer"&gt;https://github.com/mzivkovicdev/spring-crud-generator&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It is not the flashiest kind of release, but it is the kind of release that makes a tool more usable in real life.&lt;/p&gt;

</description>
      <category>java</category>
      <category>springboot</category>
      <category>opensource</category>
      <category>ai</category>
    </item>
    <item>
      <title>Spring CRUD Generator v1.5.0: Better Spec Consistency, CI Integration Tests, and AI-Friendly Spec Authoring</title>
      <dc:creator>Marko</dc:creator>
      <pubDate>Wed, 11 Mar 2026 15:44:14 +0000</pubDate>
      <link>https://forem.com/mzivkovicdev/spring-crud-generator-v150-better-spec-consistency-ci-integration-tests-and-ai-friendly-spec-1h58</link>
      <guid>https://forem.com/mzivkovicdev/spring-crud-generator-v150-better-spec-consistency-ci-integration-tests-and-ai-friendly-spec-1h58</guid>
      <description>&lt;p&gt;I’ve just released &lt;strong&gt;Spring CRUD Generator v1.5.0&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;It’s an open-source &lt;strong&gt;Maven plugin&lt;/strong&gt; that generates Spring Boot CRUD code from a YAML/JSON configuration. The project can generate entities, DTOs, mappers, services, business services, controllers, Flyway migrations, Docker resources, and optional OpenAPI-related pieces.&lt;/p&gt;

&lt;p&gt;This release is focused on three things:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;better &lt;strong&gt;spec consistency&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;stronger &lt;strong&gt;CI verification&lt;/strong&gt; for generated output&lt;/li&gt;
&lt;li&gt;a smoother &lt;strong&gt;developer experience&lt;/strong&gt; when writing and evolving specs&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;One of the more interesting improvements in this version is better &lt;strong&gt;GitHub Copilot support and autocomplete&lt;/strong&gt; for project specs.&lt;/p&gt;

&lt;p&gt;I don’t want to oversell that as “AI magic”, because that’s not what this project is about. The goal is simpler: if you’re editing a larger generator config, the experience is now more natural for AI-assisted authoring and easier to work with in day-to-day development.&lt;/p&gt;

&lt;h2&gt;
  
  
  What’s new in v1.5.0
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1) &lt;code&gt;basePath&lt;/code&gt; vs &lt;code&gt;basepath&lt;/code&gt; consistency fix
&lt;/h3&gt;

&lt;p&gt;There was an inconsistency between documentation and code:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;documentation used &lt;code&gt;basePath&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;code also accepted &lt;code&gt;basepath&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That is now cleaned up.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;basePath&lt;/code&gt; is the documented form going forward, while &lt;code&gt;basepath&lt;/code&gt; is still supported for backward compatibility but is now deprecated.&lt;/p&gt;

&lt;h3&gt;
  
  
  2) Integration tests for the generator project
&lt;/h3&gt;

&lt;p&gt;This does &lt;strong&gt;not&lt;/strong&gt; mean the generator now creates integration tests.&lt;/p&gt;

&lt;p&gt;Instead, integration tests were added to the &lt;strong&gt;generator project itself&lt;/strong&gt;, and they now run in &lt;strong&gt;GitHub CI&lt;/strong&gt;. The purpose is to detect generated-code inconsistencies earlier when new changes are introduced.&lt;/p&gt;

&lt;p&gt;That gives the project a more reliable feedback loop and makes future changes safer.&lt;/p&gt;

&lt;h3&gt;
  
  
  3) &lt;code&gt;relation.uniqueItems&lt;/code&gt; support
&lt;/h3&gt;

&lt;p&gt;A new field was added:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;relation&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;uniqueItems&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This can be used for generating &lt;code&gt;Set&lt;/code&gt;-based relations for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;OneToMany&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;ManyToMany&lt;/code&gt; &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is useful when uniqueness is part of the intended model and a &lt;code&gt;Set&lt;/code&gt; is a better fit than a &lt;code&gt;List&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  4) Fix for JSON collection imports in business services
&lt;/h3&gt;

&lt;p&gt;There was a bug in business services when using:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;JSON&amp;lt;List&amp;lt;T&amp;gt;&amp;gt;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;JSON&amp;lt;Set&amp;lt;T&amp;gt;&amp;gt;&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In those cases, &lt;code&gt;List&lt;/code&gt; / &lt;code&gt;Set&lt;/code&gt; imports are now generated correctly.&lt;/p&gt;

&lt;h3&gt;
  
  
  5) Better GitHub Copilot support + autocomplete
&lt;/h3&gt;

&lt;p&gt;Spec authoring now works better with GitHub Copilot and autocomplete.&lt;/p&gt;

&lt;p&gt;This is especially useful if your generator config is growing over time and you want a smoother editing experience without constantly double-checking every field manually.&lt;/p&gt;

&lt;h3&gt;
  
  
  6) Security policy added
&lt;/h3&gt;

&lt;p&gt;The project now includes a security policy.&lt;/p&gt;

&lt;h3&gt;
  
  
  7) Documentation update
&lt;/h3&gt;

&lt;p&gt;The documentation was updated to be more readable and easier to navigate.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why this release matters
&lt;/h3&gt;

&lt;p&gt;Most generator improvements are not flashy.&lt;/p&gt;

&lt;p&gt;But consistency fixes, CI-backed verification, relation modeling improvements, and better tooling support are exactly the things that make a code generator easier to trust over time.&lt;/p&gt;

&lt;p&gt;That was the main focus of v1.5.0: making the generator more predictable, safer to evolve, and more comfortable to use on real projects.&lt;/p&gt;

&lt;h3&gt;
  
  
  Links
&lt;/h3&gt;

&lt;p&gt;GitHub repo: &lt;a href="https://github.com/mzivkovicdev/spring-crud-generator" rel="noopener noreferrer"&gt;https://github.com/mzivkovicdev/spring-crud-generator&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Release: &lt;a href="https://github.com/mzivkovicdev/spring-crud-generator/releases/tag/v1.5.0" rel="noopener noreferrer"&gt;https://github.com/mzivkovicdev/spring-crud-generator/releases/tag/v1.5.0&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Demo project: &lt;a href="https://github.com/mzivkovicdev/spring-crud-generator-demo" rel="noopener noreferrer"&gt;https://github.com/mzivkovicdev/spring-crud-generator-demo&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you work with Spring Boot and prefer declarative project setup over repetitive CRUD boilerplate, this release may be useful.&lt;/p&gt;

</description>
      <category>java</category>
      <category>springboot</category>
      <category>githubcopilot</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Spring CRUD Generator — v1.4.0 Adds Soft Delete and Better Validation</title>
      <dc:creator>Marko</dc:creator>
      <pubDate>Wed, 04 Mar 2026 14:43:02 +0000</pubDate>
      <link>https://forem.com/mzivkovicdev/i-built-a-maven-plugin-that-generates-spring-boot-crud-code-v140-adds-soft-delete-and-better-2gp4</link>
      <guid>https://forem.com/mzivkovicdev/i-built-a-maven-plugin-that-generates-spring-boot-crud-code-v140-adds-soft-delete-and-better-2gp4</guid>
      <description>&lt;p&gt;I’ve just released &lt;strong&gt;Spring CRUD Generator v1.4.0&lt;/strong&gt; 🎉&lt;/p&gt;

&lt;p&gt;It’s an open-source Maven plugin that generates Spring Boot CRUD code from a YAML/JSON configuration — entities, DTOs, mappers, services, controllers, Flyway migrations, Docker resources, OpenAPI support, caching configuration, and more.&lt;/p&gt;

&lt;p&gt;Repository: &lt;a href="https://github.com/mzivkovicdev/spring-crud-generator" rel="noopener noreferrer"&gt;https://github.com/mzivkovicdev/spring-crud-generator&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What’s new in v1.4.0
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1) Stricter input spec validation (and better error reporting)
&lt;/h3&gt;

&lt;p&gt;Validation is now significantly stricter, but also more helpful.&lt;/p&gt;

&lt;p&gt;Instead of failing fast on the first invalid field, the generator now validates the &lt;strong&gt;entire entity&lt;/strong&gt; and &lt;strong&gt;collects multiple validation errors&lt;/strong&gt; before failing. Entities are still validated one-by-one, but you get a complete list of issues per entity, which makes fixing configuration problems much faster.&lt;/p&gt;

&lt;p&gt;On top of that, relation validation got a major upgrade. The input spec is now validated for common (and painful) relation mistakes, such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;invalid relation type values&lt;/li&gt;
&lt;li&gt;relations referencing target models that don’t exist&lt;/li&gt;
&lt;li&gt;invalid or missing join table configuration&lt;/li&gt;
&lt;li&gt;invalid join column / inverse join column naming&lt;/li&gt;
&lt;li&gt;missing join table for &lt;code&gt;Many-to-Many&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;unsupported mapping combinations (e.g. &lt;code&gt;orphanRemoval&lt;/code&gt; on &lt;code&gt;Many-to-Many&lt;/code&gt; / &lt;code&gt;Many-to-One&lt;/code&gt;)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It also enforces &lt;code&gt;lower_snake_case&lt;/code&gt; naming rules for join table and join column-related names, which helps avoid broken or inconsistent schema artifacts.&lt;/p&gt;

&lt;h3&gt;
  
  
  2) Soft delete support
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Soft delete&lt;/strong&gt; is now available as a feature. This helps when your domain needs logical deletion (audit/history, restore flows, etc.) without physically removing records.&lt;/p&gt;

&lt;h3&gt;
  
  
  3) &lt;code&gt;orphanRemoval&lt;/code&gt; support for relations
&lt;/h3&gt;

&lt;p&gt;Relations now support an &lt;code&gt;orphanRemoval&lt;/code&gt; parameter. In addition, validation prevents unsupported usage — specifically, orphan removal is rejected for &lt;code&gt;Many-to-Many&lt;/code&gt; and &lt;code&gt;Many-to-One&lt;/code&gt; relations to avoid generating invalid JPA mappings.&lt;/p&gt;

&lt;h3&gt;
  
  
  4) Hazelcast caching support (incl. Docker Compose)
&lt;/h3&gt;

&lt;p&gt;Caching support now includes &lt;strong&gt;Hazelcast&lt;/strong&gt;, along with cache configuration and Docker Compose resources to make it easier to spin up the required infrastructure.&lt;/p&gt;

&lt;h2&gt;
  
  
  Quick start (Maven)
&lt;/h2&gt;

&lt;p&gt;If you want to try it out quickly:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;plugin&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;dev.markozivkovic&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;spring-crud-generator&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;version&amp;gt;&lt;/span&gt;1.4.0&lt;span class="nt"&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/plugin&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;(See the repo for full configuration examples and the demo project.)&lt;/p&gt;

&lt;h2&gt;
  
  
  Upgrade notes
&lt;/h2&gt;

&lt;p&gt;If you’re upgrading from an earlier version: expect &lt;strong&gt;stricter validation&lt;/strong&gt;. Specs that previously “worked by accident” may now fail with explicit, actionable errors.&lt;/p&gt;

&lt;p&gt;The most common things to double-check are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;relation type values&lt;/li&gt;
&lt;li&gt;target model names in relations&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Many-to-Many&lt;/code&gt; definitions missing a join table&lt;/li&gt;
&lt;li&gt;join table / join column naming (must be &lt;code&gt;lower_snake_case&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;avoiding &lt;code&gt;orphanRemoval&lt;/code&gt; on &lt;code&gt;Many-to-Many&lt;/code&gt; / &lt;code&gt;Many-to-One&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Links
&lt;/h2&gt;

&lt;p&gt;Repo: &lt;a href="https://github.com/mzivkovicdev/spring-crud-generator" rel="noopener noreferrer"&gt;https://github.com/mzivkovicdev/spring-crud-generator&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you try v1.4.0, I’d love feedback — especially on the new validation behavior and the Hazelcast setup.&lt;/p&gt;

</description>
      <category>java</category>
      <category>springboot</category>
      <category>opensource</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Why I built a Spring CRUD Generator as a Maven plugin (not a CLI)</title>
      <dc:creator>Marko</dc:creator>
      <pubDate>Fri, 27 Feb 2026 10:41:48 +0000</pubDate>
      <link>https://forem.com/mzivkovicdev/why-i-built-a-spring-crud-generator-as-a-maven-plugin-not-a-cli-pfl</link>
      <guid>https://forem.com/mzivkovicdev/why-i-built-a-spring-crud-generator-as-a-maven-plugin-not-a-cli-pfl</guid>
      <description>&lt;p&gt;Most Spring Boot projects start the same way.&lt;/p&gt;

&lt;p&gt;You define entities, then you repeat the same scaffolding:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;repositories
&lt;/li&gt;
&lt;li&gt;services (and often a “business service” layer)
&lt;/li&gt;
&lt;li&gt;DTOs + mapping
&lt;/li&gt;
&lt;li&gt;controllers
&lt;/li&gt;
&lt;li&gt;validation and error handling conventions
&lt;/li&gt;
&lt;li&gt;docs (OpenAPI/Swagger)
&lt;/li&gt;
&lt;li&gt;migrations (Flyway)
&lt;/li&gt;
&lt;li&gt;Docker bits
&lt;/li&gt;
&lt;li&gt;tests + test data setup
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;None of that is &lt;em&gt;hard&lt;/em&gt;. It’s just &lt;em&gt;expensive&lt;/em&gt; in terms of time and focus—especially when you’re doing it for the 10th time.&lt;/p&gt;

&lt;p&gt;That’s why I built &lt;strong&gt;Spring CRUD Generator&lt;/strong&gt;: an open-source tool that generates a production-ready Spring Boot backend baseline from a single YAML/JSON spec—CRUD layers, optional Flyway migrations, optional OpenAPI/Swagger, optional GraphQL, optional Docker resources, optional caching, and optional tests/test data generation.&lt;/p&gt;

&lt;p&gt;And I made it a &lt;strong&gt;Maven plugin&lt;/strong&gt; on purpose.&lt;/p&gt;

&lt;p&gt;This post is about &lt;em&gt;why&lt;/em&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  The goal: make the “baseline” reproducible
&lt;/h2&gt;

&lt;p&gt;I wasn’t trying to generate “toy CRUD” code.&lt;/p&gt;

&lt;p&gt;The goal was: generate a baseline you’d actually keep in a real project:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;JPA/Hibernate entities&lt;/li&gt;
&lt;li&gt;repositories, services, business services&lt;/li&gt;
&lt;li&gt;transfer objects + mappers&lt;/li&gt;
&lt;li&gt;REST controllers&lt;/li&gt;
&lt;li&gt;optional GraphQL schemas/resolvers&lt;/li&gt;
&lt;li&gt;optional OpenAPI/Swagger resources&lt;/li&gt;
&lt;li&gt;optional Flyway migrations&lt;/li&gt;
&lt;li&gt;optional Dockerfile + docker-compose&lt;/li&gt;
&lt;li&gt;optional unit tests + test data (Instancio / Podam)&lt;/li&gt;
&lt;li&gt;optional caching (Redis / Caffeine)&lt;/li&gt;
&lt;li&gt;optional optimistic locking&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In other words: &lt;strong&gt;reduce boilerplate&lt;/strong&gt;, keep structure consistent across projects, and leave developers with more time for domain logic.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why Maven plugin (instead of a CLI)?
&lt;/h2&gt;

&lt;p&gt;A CLI is tempting. It’s easy to ship, easy to run, and it feels flexible.&lt;/p&gt;

&lt;p&gt;But after using generators in multiple teams/projects, the same friction always shows up:&lt;/p&gt;

&lt;h3&gt;
  
  
  1) “Works on my machine” is real for generators too
&lt;/h3&gt;

&lt;p&gt;A CLI easily becomes something that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;one person runs locally&lt;/li&gt;
&lt;li&gt;others forget to run&lt;/li&gt;
&lt;li&gt;CI doesn’t enforce&lt;/li&gt;
&lt;li&gt;output drifts&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When generation becomes &lt;strong&gt;part of the build&lt;/strong&gt;, you remove that entire class of problems.&lt;/p&gt;

&lt;p&gt;With a Maven plugin, generation is a &lt;em&gt;first-class build step&lt;/em&gt;. If you can build the project, you can generate the baseline—consistently.&lt;/p&gt;

&lt;h3&gt;
  
  
  2) Reproducibility requires versioning the generator itself
&lt;/h3&gt;

&lt;p&gt;If your generator version isn’t pinned, you eventually get:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“Which version did you run when you generated this?”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;With Maven, the generator version is just a dependency coordinate.&lt;/p&gt;

&lt;p&gt;That gives you:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;repeatable outputs across machines/environments&lt;/li&gt;
&lt;li&gt;predictable upgrades (change version, review diff)&lt;/li&gt;
&lt;li&gt;easy CI consistency&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  3) It fits naturally into existing Java workflows
&lt;/h3&gt;

&lt;p&gt;Spring Boot projects already live in Maven/Gradle land.&lt;br&gt;
So instead of adding “yet another tool,” a Maven plugin integrates with what teams already use:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;local build&lt;/li&gt;
&lt;li&gt;CI pipeline&lt;/li&gt;
&lt;li&gt;multi-module setups&lt;/li&gt;
&lt;li&gt;profiles and environments&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  4) Generated code stays transparent and owned by the project
&lt;/h3&gt;

&lt;p&gt;One of my strongest constraints was:&lt;br&gt;
&lt;strong&gt;no runtime magic and no hidden framework layer&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The generator outputs code into your project. You can read it, modify it, debug it, and evolve it.&lt;br&gt;
The plugin accelerates the start—then you keep full control.&lt;/p&gt;


&lt;h2&gt;
  
  
  The migration angle: why Maven is &lt;em&gt;especially&lt;/em&gt; important
&lt;/h2&gt;

&lt;p&gt;Migrations are where projects drift the fastest.&lt;/p&gt;

&lt;p&gt;If you generate code but migrations are manual (or inconsistent), you still lose time—and you introduce risk.&lt;/p&gt;

&lt;p&gt;That’s why the generator supports Flyway migrations based on differences between:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the current YAML/JSON spec&lt;/li&gt;
&lt;li&gt;the previous generator state stored on disk&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It maintains a state file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.crud-generator/migration-state.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This file allows the generator to detect schema changes and generate incremental migrations in common cases (like adding tables or adding/removing columns), without requiring you to hand-write SQL every time you tweak a model.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Important safety rule&lt;/code&gt;: table deletion is intentionally not generated.&lt;br&gt;
If an entity disappears from the spec, the generator does not drop the table automatically. That’s a deliberate guardrail to reduce accidental data loss.&lt;/p&gt;

&lt;p&gt;This is another reason Maven helps: state + migrations become part of the build + repo workflow, not “something someone ran locally.”&lt;/p&gt;




&lt;h2&gt;
  
  
  Spec-first: one file to describe your backend baseline
&lt;/h2&gt;

&lt;p&gt;I wanted a single source of truth.&lt;/p&gt;

&lt;p&gt;Instead of having your truth scattered across:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;entity annotations&lt;/li&gt;
&lt;li&gt;controller patterns&lt;/li&gt;
&lt;li&gt;DTO mapping rules&lt;/li&gt;
&lt;li&gt;documentation configuration&lt;/li&gt;
&lt;li&gt;migration scripts&lt;/li&gt;
&lt;li&gt;Docker resources&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;…the generator reads a spec (YAML/JSON) that describes entities, fields, relationships, constraints, and optional features.&lt;/p&gt;

&lt;p&gt;Then it generates the baseline around that spec.&lt;/p&gt;

&lt;p&gt;That’s the whole philosophy: make the boring parts declarative.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why I didn’t build an IDE plugin first
&lt;/h2&gt;

&lt;p&gt;IDE plugins can be great—especially for discoverability.&lt;/p&gt;

&lt;p&gt;But they also:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;couple you to an editor ecosystem&lt;/li&gt;
&lt;li&gt;often lag behind build tool integration&lt;/li&gt;
&lt;li&gt;don’t guarantee CI reproducibility&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For me, correctness and repeatability mattered more than UI convenience.&lt;/p&gt;

&lt;p&gt;Once generation is stable in the build pipeline, IDE tooling becomes an optional layer—not the foundation.&lt;/p&gt;




&lt;h2&gt;
  
  
  What I wanted to optimize for
&lt;/h2&gt;

&lt;p&gt;This is what “success” looks like for this generator:&lt;/p&gt;

&lt;p&gt;✅ You start a Spring Boot project and skip repetitive scaffolding&lt;br&gt;
✅ Your project structure stays consistent across teams/projects&lt;br&gt;
✅ Your generator runs the same in CI as it does locally&lt;br&gt;
✅ You can upgrade generator versions intentionally&lt;br&gt;
✅ You keep full control over the generated code&lt;br&gt;
✅ Migrations remain safe and incremental&lt;br&gt;
✅ You spend time on business logic, not boilerplate&lt;/p&gt;




&lt;h2&gt;
  
  
  Final thought
&lt;/h2&gt;

&lt;p&gt;I didn’t choose Maven because it was trendy.&lt;br&gt;
I chose it because generators are only truly valuable when they are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;reproducible&lt;/li&gt;
&lt;li&gt;versioned&lt;/li&gt;
&lt;li&gt;enforceable&lt;/li&gt;
&lt;li&gt;consistent across environments&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A Maven plugin turns code generation from a “tool you sometimes run” into a reliable part of your engineering workflow.&lt;/p&gt;

&lt;p&gt;If you want to try it, repo: &lt;a href="https://github.com/mzivkovicdev/spring-crud-generator" rel="noopener noreferrer"&gt;https://github.com/mzivkovicdev/spring-crud-generator&lt;/a&gt;&lt;/p&gt;

</description>
      <category>java</category>
      <category>springboot</category>
      <category>web</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Spring CRUD Generator v1.3.0 Released - MariaDB support + Optional Null Exclusion in REST Responses</title>
      <dc:creator>Marko</dc:creator>
      <pubDate>Tue, 24 Feb 2026 15:27:16 +0000</pubDate>
      <link>https://forem.com/mzivkovicdev/spring-crud-generator-v130-released-160l</link>
      <guid>https://forem.com/mzivkovicdev/spring-crud-generator-v130-released-160l</guid>
      <description>&lt;p&gt;I’ve just released &lt;strong&gt;Spring CRUD Generator v1.3.0&lt;/strong&gt; 🎉&lt;/p&gt;

&lt;p&gt;If you haven’t seen it before, &lt;strong&gt;Spring CRUD Generator&lt;/strong&gt; is an open-source Maven plugin that generates &lt;strong&gt;Spring Boot CRUD code&lt;/strong&gt; from a &lt;strong&gt;YAML/JSON project config&lt;/strong&gt; — including:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;entities&lt;/li&gt;
&lt;li&gt;transfer objects (DTOs)&lt;/li&gt;
&lt;li&gt;mappers&lt;/li&gt;
&lt;li&gt;services and business services&lt;/li&gt;
&lt;li&gt;controllers&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;…and optionally:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;OpenAPI/Swagger resources&lt;/li&gt;
&lt;li&gt;GraphQL resolvers&lt;/li&gt;
&lt;li&gt;Flyway migrations&lt;/li&gt;
&lt;li&gt;Docker resources&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The goal is simple: &lt;strong&gt;generate the repetitive CRUD boilerplate fast&lt;/strong&gt;, keep the structure consistent, and let you focus on business logic.&lt;/p&gt;




&lt;h2&gt;
  
  
  What’s new in v1.3.0
&lt;/h2&gt;

&lt;h3&gt;
  
  
  ✅ Full MariaDB support
&lt;/h3&gt;

&lt;p&gt;The generator is now fully compatible with &lt;strong&gt;MariaDB&lt;/strong&gt;, in addition to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;MySQL&lt;/li&gt;
&lt;li&gt;PostgreSQL&lt;/li&gt;
&lt;li&gt;MSSQL&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This release also includes related updates for MariaDB support across the ecosystem around the generator:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Flyway scripts&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Docker Compose setup&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Database compatibility support&lt;/strong&gt; in the generator and generated code&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you’re using MariaDB in your projects, you can now use the generator without workarounds.&lt;/p&gt;




&lt;h3&gt;
  
  
  ✅ New property: &lt;code&gt;rest.response.excludeNull&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;A new additional property is now available:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight properties"&gt;&lt;code&gt;&lt;span class="py"&gt;rest.response.excludeNull&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When enabled, generated REST responses will exclude &lt;code&gt;null&lt;/code&gt; fields from JSON output.&lt;/p&gt;

&lt;p&gt;This is useful when you want:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;cleaner API responses&lt;/li&gt;
&lt;li&gt;smaller payloads&lt;/li&gt;
&lt;li&gt;more controlled serialization behavior&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It’s compatible with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Spring Boot 3&lt;/li&gt;
&lt;li&gt;Spring Boot 4&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Why I added this
&lt;/h3&gt;

&lt;p&gt;Two things kept coming up:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;MariaDB support was a natural next step after MySQL/PostgreSQL/MSSQL compatibility.&lt;/li&gt;
&lt;li&gt;In many APIs, people prefer not returning &lt;code&gt;null&lt;/code&gt; fields in responses — so adding a generator-level switch made sense.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This release is focused on making the generated projects more practical for real-world setups.&lt;/p&gt;

&lt;h2&gt;
  
  
  Links
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Repository&lt;/strong&gt;: &lt;a href="https://github.com/mzivkovicdev/spring-crud-generator" rel="noopener noreferrer"&gt;https://github.com/mzivkovicdev/spring-crud-generator&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Release (v1.3.0)&lt;/strong&gt;: &lt;a href="https://github.com/mzivkovicdev/spring-crud-generator/releases/tag/v1.3.0" rel="noopener noreferrer"&gt;https://github.com/mzivkovicdev/spring-crud-generator/releases/tag/v1.3.0&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Demo project&lt;/strong&gt;: &lt;a href="https://github.com/mzivkovicdev/spring-crud-generator-demo" rel="noopener noreferrer"&gt;https://github.com/mzivkovicdev/spring-crud-generator-demo&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Feedback welcome 🙌
&lt;/h2&gt;

&lt;p&gt;If you try it, I’d really appreciate feedback — especially on:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;MariaDB compatibility&lt;/li&gt;
&lt;li&gt;Flyway script behavior&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;rest.response.excludeNull&lt;/code&gt; behavior in generated APIs&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Also happy to discuss implementation details and tradeoffs behind the generator.&lt;/p&gt;

</description>
      <category>java</category>
      <category>springboot</category>
      <category>opensource</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Spring Crud Generator v1.2.0 — Improved DB Compatibility, JSON Collections, and Reliable Docker Runs</title>
      <dc:creator>Marko</dc:creator>
      <pubDate>Fri, 20 Feb 2026 10:32:00 +0000</pubDate>
      <link>https://forem.com/mzivkovicdev/spring-crud-generator-v120-improved-db-compatibility-json-collections-and-reliable-docker-runs-l1o</link>
      <guid>https://forem.com/mzivkovicdev/spring-crud-generator-v120-improved-db-compatibility-json-collections-and-reliable-docker-runs-l1o</guid>
      <description>&lt;p&gt;v1.2.0 is all about making the generator smoother to use in real projects: more predictable migrations across databases, fewer Docker Compose surprises, and better JSON support for collection-based fields. Along the way, there’s also internal refactoring to keep the codebase easier to maintain and extend.&lt;/p&gt;

&lt;h3&gt;
  
  
  Highlights
&lt;/h3&gt;

&lt;h4&gt;
  
  
  ✅ Better database migration compatibility
&lt;/h4&gt;

&lt;p&gt;This release improves Flyway script generation so migrations behave more consistently across &lt;strong&gt;MySQL, MariaDB, MSSQL, and PostgreSQL&lt;/strong&gt;. The goal here is simple: fewer “works on my DB” moments when switching environments or adding a second database target.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;More robust Flyway migration output for cross-database scenarios
&lt;/li&gt;
&lt;li&gt;Improved compatibility with newer MySQL versions (&lt;strong&gt;&amp;gt; 8.4&lt;/strong&gt;)
&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  🧠 JSON type support — now with collections
&lt;/h4&gt;

&lt;p&gt;The JSON type has been extended to better match how modern APIs model data. In addition to single-object JSON fields, you can now generate JSON columns for collections:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;JSON&amp;lt;List&amp;lt;Type&amp;gt;&amp;gt;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;JSON&amp;lt;Set&amp;lt;Type&amp;gt;&amp;gt;&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This makes it much easier to model things like tags, attributes, nested configs, and other “structured but flexible” data without bending the domain model.&lt;/p&gt;

&lt;h4&gt;
  
  
  🐳 Docker Compose that behaves like you expect
&lt;/h4&gt;

&lt;p&gt;If you’ve ever had your Spring Boot container start &lt;em&gt;before&lt;/em&gt; the database is ready (and crash/retry until it is), this update fixes that at the Compose level.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Added &lt;strong&gt;healthchecks&lt;/strong&gt; so the application starts only after database services are actually ready&lt;/li&gt;
&lt;li&gt;Fixed Docker Compose configuration around &lt;strong&gt;exposed vs internal ports&lt;/strong&gt;, reducing confusion and runtime issues&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Fixes
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Fixed Flyway scripts when using &lt;strong&gt;reserved SQL keywords&lt;/strong&gt; (reserved keywords are now supported)&lt;/li&gt;
&lt;li&gt;Fixed &lt;strong&gt;unique constraint naming&lt;/strong&gt; for consistent, correct constraint generation&lt;/li&gt;
&lt;li&gt;Updated &lt;code&gt;.openapi-generator-ignore&lt;/code&gt; to avoid regenerating/overwriting:

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;pom.xml&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;README.md&lt;/code&gt;, &lt;code&gt;Readme.md&lt;/code&gt;, &lt;code&gt;readme.md&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h3&gt;
  
  
  Internal Improvements
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Refactored internal structure to improve maintainability and future extensibility&lt;/li&gt;
&lt;li&gt;Added a &lt;strong&gt;project banner&lt;/strong&gt; that prints useful runtime metadata (version + source/output paths), which helps a lot when running generator pipelines or debugging CI logs&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Demo Repository
&lt;/h3&gt;

&lt;p&gt;To make it easier to see the expected output and integration flow, there’s now a dedicated demo repository:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/mzivkovicdev/spring-crud-generator-demo" rel="noopener noreferrer"&gt;https://github.com/mzivkovicdev/spring-crud-generator-demo&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;If you’re upgrading from earlier versions, v1.2.0 should be a drop-in update in most setups. The main benefits will show up immediately if you target multiple DBs, rely on JSON-mapped fields, or run everything through Docker Compose.&lt;br&gt;
Repo: &lt;a href="https://github.com/mzivkovicdev/spring-crud-generator" rel="noopener noreferrer"&gt;https://github.com/mzivkovicdev/spring-crud-generator&lt;/a&gt;&lt;/p&gt;

</description>
      <category>springboot</category>
      <category>java</category>
      <category>webdev</category>
      <category>programming</category>
    </item>
    <item>
      <title>Spring Crud Generator v1.2.0 — Improved DB Compatibility, JSON Collections, and More Reliable Docker Runs</title>
      <dc:creator>Marko</dc:creator>
      <pubDate>Thu, 19 Feb 2026 23:22:22 +0000</pubDate>
      <link>https://forem.com/mzivkovicdev/spring-crud-generator-v120-improved-db-compatibility-json-collections-and-more-reliable-485e</link>
      <guid>https://forem.com/mzivkovicdev/spring-crud-generator-v120-improved-db-compatibility-json-collections-and-more-reliable-485e</guid>
      <description>&lt;p&gt;v1.2.0 is all about making the generator smoother to use in real projects: more predictable migrations across databases, fewer Docker Compose surprises, and better JSON support for collection-based fields. Along the way, there’s also internal refactoring to keep the codebase easier to maintain and extend.&lt;/p&gt;

&lt;h3&gt;
  
  
  Highlights
&lt;/h3&gt;

&lt;h4&gt;
  
  
  ✅ Better database migration compatibility
&lt;/h4&gt;

&lt;p&gt;This release improves Flyway script generation so migrations behave more consistently across &lt;strong&gt;MySQL, MariaDB, MSSQL, and PostgreSQL&lt;/strong&gt;. The goal here is simple: fewer “works on my DB” moments when switching environments or adding a second database target.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;More robust Flyway migration output for cross-database scenarios
&lt;/li&gt;
&lt;li&gt;Improved compatibility with newer MySQL versions (&lt;strong&gt;&amp;gt; 8.4&lt;/strong&gt;)
&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  🧠 JSON type support — now with collections
&lt;/h4&gt;

&lt;p&gt;The JSON type has been extended to better match how modern APIs model data. In addition to single-object JSON fields, you can now generate JSON columns for collections:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;JSON&amp;lt;List&amp;lt;Type&amp;gt;&amp;gt;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;JSON&amp;lt;Set&amp;lt;Type&amp;gt;&amp;gt;&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This makes it much easier to model things like tags, attributes, nested configs, and other “structured but flexible” data without bending the domain model.&lt;/p&gt;

&lt;h4&gt;
  
  
  🐳 Docker Compose that behaves like you expect
&lt;/h4&gt;

&lt;p&gt;If you’ve ever had your Spring Boot container start &lt;em&gt;before&lt;/em&gt; the database is ready (and crash/retry until it is), this update fixes that at the Compose level.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Added &lt;strong&gt;healthchecks&lt;/strong&gt; so the application starts only after database services are actually ready&lt;/li&gt;
&lt;li&gt;Fixed Docker Compose configuration around &lt;strong&gt;exposed vs internal ports&lt;/strong&gt;, reducing confusion and runtime issues&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Fixes
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Fixed Flyway scripts when using &lt;strong&gt;reserved SQL keywords&lt;/strong&gt; (reserved keywords are now supported)&lt;/li&gt;
&lt;li&gt;Fixed &lt;strong&gt;unique constraint naming&lt;/strong&gt; for consistent, correct constraint generation&lt;/li&gt;
&lt;li&gt;Updated &lt;code&gt;.openapi-generator-ignore&lt;/code&gt; to avoid regenerating/overwriting:

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;pom.xml&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;README.md&lt;/code&gt;, &lt;code&gt;Readme.md&lt;/code&gt;, &lt;code&gt;readme.md&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h3&gt;
  
  
  Internal Improvements
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Refactored internal structure to improve maintainability and future extensibility&lt;/li&gt;
&lt;li&gt;Added a &lt;strong&gt;project banner&lt;/strong&gt; that prints useful runtime metadata (version + source/output paths), which helps a lot when running generator pipelines or debugging CI logs&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Demo Repository
&lt;/h3&gt;

&lt;p&gt;To make it easier to see the expected output and integration flow, there’s now a dedicated demo repository:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/mzivkovicdev/spring-crud-generator-demo" rel="noopener noreferrer"&gt;https://github.com/mzivkovicdev/spring-crud-generator-demo&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;If you’re upgrading from earlier versions, v1.2.0 should be a drop-in update in most setups. The main benefits will show up immediately if you target multiple DBs, rely on JSON-mapped fields, or run everything through Docker Compose.&lt;br&gt;
Repo: &lt;a href="https://github.com/mzivkovicdev/spring-crud-generator" rel="noopener noreferrer"&gt;https://github.com/mzivkovicdev/spring-crud-generator&lt;/a&gt;&lt;/p&gt;

</description>
      <category>database</category>
      <category>docker</category>
      <category>springboot</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Spring CRUD Generator now has a full Demo Project (generated from a real spec)</title>
      <dc:creator>Marko</dc:creator>
      <pubDate>Wed, 18 Feb 2026 13:56:19 +0000</pubDate>
      <link>https://forem.com/mzivkovicdev/spring-crud-generator-now-has-a-full-demo-project-generated-from-a-real-spec-1j1d</link>
      <guid>https://forem.com/mzivkovicdev/spring-crud-generator-now-has-a-full-demo-project-generated-from-a-real-spec-1j1d</guid>
      <description>&lt;p&gt;When you build a code generator, the hardest part isn’t shipping features — it’s earning trust.&lt;br&gt;
People want to answer questions like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;“Does it actually work end-to-end?”&lt;/li&gt;
&lt;li&gt;“Is the output consistent and buildable?”&lt;/li&gt;
&lt;li&gt;“What does the generated code really look like?”&lt;/li&gt;
&lt;li&gt;“Is this stable enough to try on a real project?”&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That’s why I’ve added a dedicated Spring CRUD Generator Demo repository: a complete, buildable project that exists primarily to demonstrate that the generator works reliably and produces production-style output.&lt;/p&gt;
&lt;h2&gt;
  
  
  What is the demo project?
&lt;/h2&gt;

&lt;p&gt;Spring CRUD Generator Demo is a repository that showcases the generated output of Spring CRUD Generator in a realistic setup. It’s meant to be a reference output you can inspect anytime:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;browse the package structure and layering&lt;/li&gt;
&lt;li&gt;review generated DTOs, validation, mapping, services, controllers&lt;/li&gt;
&lt;li&gt;see how migrations/resources/tests/docker artifacts look in a real repo&lt;/li&gt;
&lt;li&gt;confirm the project builds like a normal Spring Boot application&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In short: it’s a “proof by example” repository.&lt;/p&gt;
&lt;h2&gt;
  
  
  The spec used to generate the demo
&lt;/h2&gt;

&lt;p&gt;The demo project is generated from the full example CRUD spec from the main generator repository.&lt;/p&gt;

&lt;p&gt;That means the demo isn’t a cherry-picked minimal case — it’s generated from a spec that enables a broad set of features and produces a meaningful codebase.&lt;/p&gt;
&lt;h2&gt;
  
  
  What’s enabled in the demo (all features ON)
&lt;/h2&gt;

&lt;p&gt;The demo is built to be feature-rich. The idea is to show a “full stack” backend baseline generated from configuration, including:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Database: PostgreSQL&lt;/li&gt;
&lt;li&gt;Java: 21&lt;/li&gt;
&lt;li&gt;Spring Boot: 4.x&lt;/li&gt;
&lt;li&gt;Optimistic locking: enabled (with retry/backoff config)&lt;/li&gt;
&lt;li&gt;Docker: Dockerfile + docker-compose (app + db)&lt;/li&gt;
&lt;li&gt;Caching: Redis with expiration&lt;/li&gt;
&lt;li&gt;OpenAPI: API spec + generated resources&lt;/li&gt;
&lt;li&gt;GraphQL: enabled (with scalar config)&lt;/li&gt;
&lt;li&gt;Error responses: simple format&lt;/li&gt;
&lt;li&gt;Migrations: enabled&lt;/li&gt;
&lt;li&gt;Tests: unit tests + test data generation (Instancio)&lt;/li&gt;
&lt;li&gt;Additional properties: REST base path /api/v1, OSIV disabled, etc.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here’s the exact feature snapshot (as used in the config/spec context):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;database&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;postgresql&lt;/span&gt;
&lt;span class="na"&gt;javaVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;21&lt;/span&gt;
&lt;span class="na"&gt;springBootVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;4&lt;/span&gt;
&lt;span class="na"&gt;optimisticLocking&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;span class="na"&gt;docker&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;dockerfile&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
  &lt;span class="na"&gt;dockerCompose&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
  &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;eclipse-temurin&lt;/span&gt;
    &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;8080&lt;/span&gt;
  &lt;span class="na"&gt;db&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;postgres&lt;/span&gt;
    &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;5432&lt;/span&gt;
    &lt;span class="na"&gt;tag&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;latest&lt;/span&gt;
&lt;span class="na"&gt;cache&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; 
  &lt;span class="na"&gt;enabled&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
  &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;REDIS&lt;/span&gt;
  &lt;span class="na"&gt;expiration&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;5&lt;/span&gt;
&lt;span class="na"&gt;openApi&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;apiSpec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
  &lt;span class="na"&gt;generateResources&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;span class="na"&gt;graphql&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;enabled&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
  &lt;span class="na"&gt;scalarConfig&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;span class="na"&gt;errorResponse&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;simple&lt;/span&gt;
&lt;span class="na"&gt;migrationScripts&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;span class="na"&gt;tests&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;unit&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
  &lt;span class="na"&gt;dataGenerator&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;instancio&lt;/span&gt;
&lt;span class="na"&gt;additionalProperties&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;rest.basePath&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/api/v1&lt;/span&gt;
  &lt;span class="na"&gt;optimisticLocking.retry.config&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
  &lt;span class="na"&gt;optimisticLocking.retry.maxAttempts&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;5&lt;/span&gt;
  &lt;span class="na"&gt;optimisticLocking.backoff.delayMs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;100&lt;/span&gt;
  &lt;span class="na"&gt;optimisticLocking.backoff.multiplier&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;2.0&lt;/span&gt;
  &lt;span class="na"&gt;optimisticLocking.backoff.maxDelayMs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1000&lt;/span&gt;
  &lt;span class="na"&gt;spring.jpa.open-in-view&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Why a demo repo matters (especially for generators)
&lt;/h2&gt;

&lt;p&gt;Docs and screenshots help, but they don’t replace a real codebase you can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;clone&lt;/li&gt;
&lt;li&gt;build&lt;/li&gt;
&lt;li&gt;run&lt;/li&gt;
&lt;li&gt;inspect&lt;/li&gt;
&lt;li&gt;compare across versions&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A demo repository gives you a stable baseline to evaluate the generator’s output quality and consistency. It also makes regression spotting easier: as the generator evolves, you can re-generate and quickly see what changed.&lt;/p&gt;

&lt;p&gt;If you’re considering trying Spring CRUD Generator, this demo repo is the fastest way to answer:&lt;br&gt;
“Is this what I want my project skeleton to look like?”&lt;/p&gt;

&lt;h2&gt;
  
  
  Links (copy/paste)
&lt;/h2&gt;

&lt;p&gt;Spring CRUD Generator (main repo):&lt;br&gt;
&lt;a href="https://github.com/mzivkovicdev/spring-crud-generator" rel="noopener noreferrer"&gt;https://github.com/mzivkovicdev/spring-crud-generator&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Spring CRUD Generator Demo:&lt;br&gt;
&lt;a href="https://github.com/mzivkovicdev/spring-crud-generator-demo" rel="noopener noreferrer"&gt;https://github.com/mzivkovicdev/spring-crud-generator-demo&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Spec used to generate the demo (full example):&lt;br&gt;
&lt;a href="https://github.com/mzivkovicdev/spring-crud-generator/blob/master/docs/examples/crud-spec-full.yaml" rel="noopener noreferrer"&gt;https://github.com/mzivkovicdev/spring-crud-generator/blob/master/docs/examples/crud-spec-full.yaml&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Feedback welcome
&lt;/h2&gt;

&lt;p&gt;If you spot something you’d like to see improved in the generated output (structure, conventions, defaults, feature toggles), open an issue or start a discussion in the main repo. The whole point of publishing a demo project is transparency — and making it easier to iterate based on real feedback.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>springboot</category>
      <category>programming</category>
      <category>restapi</category>
    </item>
    <item>
      <title>Spring CRUD Generator v1.1.0: Field Validation, Better Redis Caching &amp; Spring Boot 3/4 Compatibility</title>
      <dc:creator>Marko</dc:creator>
      <pubDate>Tue, 10 Feb 2026 14:10:29 +0000</pubDate>
      <link>https://forem.com/mzivkovicdev/spring-crud-generator-v110-field-validation-better-redis-caching-spring-boot-34-compatibility-2f5</link>
      <guid>https://forem.com/mzivkovicdev/spring-crud-generator-v110-field-validation-better-redis-caching-spring-boot-34-compatibility-2f5</guid>
      <description>&lt;p&gt;I just released &lt;a href="https://github.com/mzivkovicdev/spring-crud-generator" rel="noopener noreferrer"&gt;&lt;strong&gt;Spring CRUD Generator v1.1.0&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This version introduces &lt;strong&gt;field-level validation&lt;/strong&gt;, improves &lt;strong&gt;Redis caching&lt;/strong&gt;, and fixes compatibility issues so the generator now works reliably with &lt;strong&gt;Spring Boot 3&lt;/strong&gt; and &lt;strong&gt;Spring Boot 4&lt;/strong&gt;. It also improves behavior when &lt;strong&gt;Open Session In View (OSIV)&lt;/strong&gt; is disabled by adding &lt;strong&gt;EntityGraph&lt;/strong&gt; support in generated resources.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Repository:&lt;/strong&gt; &lt;a href="https://github.com/mzivkovicdev/spring-crud-generator" rel="noopener noreferrer"&gt;https://github.com/mzivkovicdev/spring-crud-generator&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  What’s new in v1.1.0
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Field validation (&lt;code&gt;fields.validation&lt;/code&gt;)
&lt;/h3&gt;

&lt;p&gt;You can now configure validation rules directly in entity &lt;code&gt;fields&lt;/code&gt; using a new optional &lt;code&gt;validation&lt;/code&gt; section (required/not-null, length/range constraints, patterns, and collection size limits).&lt;br&gt;&lt;br&gt;
Regex validation is supported via &lt;code&gt;pattern&lt;/code&gt;.&lt;/p&gt;
&lt;h3&gt;
  
  
  Cache &amp;amp; Redis improvements
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Fixed generation of &lt;code&gt;@Cacheable(value=...)&lt;/code&gt; values.&lt;/li&gt;
&lt;li&gt;Added &lt;strong&gt;&lt;code&gt;HibernateLazyNullModule&lt;/code&gt;&lt;/strong&gt; to improve Redis caching behavior with Hibernate lazy-loaded entities.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  Spring Boot 3 &amp;amp; 4 compatibility
&lt;/h3&gt;

&lt;p&gt;Resolved compatibility issues — the generator is now fully compatible with &lt;strong&gt;Spring Boot 3&lt;/strong&gt; and &lt;strong&gt;Spring Boot 4&lt;/strong&gt;.&lt;/p&gt;
&lt;h3&gt;
  
  
  OSIV control + EntityGraph support
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;New configuration entry: &lt;code&gt;additionalProperties.spring.jpa.open-in-view&lt;/code&gt; (default: &lt;code&gt;false&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;When OSIV is disabled (recommended), generated resources use &lt;strong&gt;EntityGraph&lt;/strong&gt; to handle lazy relations safely.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  Improvements &amp;amp; stability
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Documentation and tests updated for the new validation model.&lt;/li&gt;
&lt;li&gt;Refactored generator internals for readability and maintainability.&lt;/li&gt;
&lt;li&gt;Fixed an NPE edge case when &lt;code&gt;min&lt;/code&gt;/&lt;code&gt;max&lt;/code&gt; validation values are not provided.&lt;/li&gt;
&lt;/ul&gt;


&lt;h2&gt;
  
  
  Updated CRUD spec YAML (short example)
&lt;/h2&gt;

&lt;p&gt;The project includes an updated &lt;strong&gt;full CRUD spec YAML&lt;/strong&gt; reference example. Below is a shortened version that highlights the new and most important parts (validation + OSIV):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;configuration&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;database&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;postgresql&lt;/span&gt;
  &lt;span class="na"&gt;javaVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;21&lt;/span&gt;
  &lt;span class="na"&gt;springBootVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;4&lt;/span&gt;
  &lt;span class="na"&gt;cache&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;enabled&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
    &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;REDIS&lt;/span&gt;
    &lt;span class="na"&gt;expiration&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;5&lt;/span&gt;
  &lt;span class="na"&gt;openApi&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;apiSpec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
  &lt;span class="na"&gt;additionalProperties&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;rest.basePath&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/api/v1&lt;/span&gt;
    &lt;span class="na"&gt;spring.jpa.open-in-view&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
&lt;span class="na"&gt;entities&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ProductModel&lt;/span&gt;
    &lt;span class="na"&gt;storageName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;product_table&lt;/span&gt;
    &lt;span class="na"&gt;fields&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;id&lt;/span&gt;
        &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Long&lt;/span&gt;
        &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;strategy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;IDENTITY&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;name&lt;/span&gt;
        &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;String&lt;/span&gt;
        &lt;span class="na"&gt;column&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;nullable&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
          &lt;span class="na"&gt;unique&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
          &lt;span class="na"&gt;length&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;10000&lt;/span&gt;
        &lt;span class="na"&gt;validation&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;required&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
          &lt;span class="na"&gt;notBlank&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
          &lt;span class="na"&gt;minLength&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;10&lt;/span&gt;
          &lt;span class="na"&gt;maxLength&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;10000&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;price&lt;/span&gt;
        &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Integer&lt;/span&gt;
        &lt;span class="na"&gt;column&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;nullable&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
        &lt;span class="na"&gt;validation&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;required&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
          &lt;span class="na"&gt;min&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
          &lt;span class="na"&gt;max&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;100&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;users&lt;/span&gt;
        &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;UserEntity&lt;/span&gt;
        &lt;span class="na"&gt;relation&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;OneToMany&lt;/span&gt;
          &lt;span class="na"&gt;fetch&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;LAZY&lt;/span&gt;
          &lt;span class="na"&gt;joinColumn&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;product_id&lt;/span&gt;
        &lt;span class="na"&gt;validation&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;required&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
          &lt;span class="na"&gt;minItems&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
          &lt;span class="na"&gt;maxItems&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;10&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;UserEntity&lt;/span&gt;
    &lt;span class="na"&gt;storageName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;user_table&lt;/span&gt;
    &lt;span class="na"&gt;fields&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;id&lt;/span&gt;
        &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Long&lt;/span&gt;
        &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;strategy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;IDENTITY&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;email&lt;/span&gt;
        &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;String&lt;/span&gt;
        &lt;span class="na"&gt;validation&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;required&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
          &lt;span class="na"&gt;email&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;password&lt;/span&gt;
        &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;String&lt;/span&gt;
        &lt;span class="na"&gt;validation&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;required&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
          &lt;span class="na"&gt;pattern&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;^(?=.*[A-Za-z])(?=.*&lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="s"&gt;d)[A-Za-z&lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="s"&gt;d]{8,}$"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Upgrade notes
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;fields.validation&lt;/code&gt; is optional — add it only where needed.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;spring.jpa.open-in-view&lt;/code&gt; defaults to &lt;code&gt;false&lt;/code&gt;. If your project relies on OSIV behavior, explicitly set it to true.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you find &lt;a href="https://github.com/mzivkovicdev/spring-crud-generator" rel="noopener noreferrer"&gt;this project&lt;/a&gt; useful, I’d really appreciate a star on &lt;a href="https://github.com/mzivkovicdev/spring-crud-generator" rel="noopener noreferrer"&gt;the repo&lt;/a&gt; — it helps a lot and keeps the momentum going.&lt;br&gt;&lt;br&gt;
Development continues, and more improvements are on the way. Thanks for the support!&lt;/p&gt;

</description>
      <category>springboot</category>
      <category>opensource</category>
      <category>webdev</category>
      <category>redis</category>
    </item>
    <item>
      <title>Spring CRUD Generator: a YAML/JSON-driven Spring Boot backend generator (version update + stability improvements)</title>
      <dc:creator>Marko</dc:creator>
      <pubDate>Tue, 27 Jan 2026 18:55:51 +0000</pubDate>
      <link>https://forem.com/mzivkovicdev/spring-crud-generator-a-yamljson-driven-spring-boot-backend-generator-version-update-stability-4mff</link>
      <guid>https://forem.com/mzivkovicdev/spring-crud-generator-a-yamljson-driven-spring-boot-backend-generator-version-update-stability-4mff</guid>
      <description>&lt;p&gt;If you saw my initial post about Spring CRUD Generator v1.0.0, this is a follow-up with a version update and a more complete overview of what the project is aiming to solve.&lt;/p&gt;

&lt;p&gt;Spring CRUD Generator is an open-source Maven plugin that generates a Spring Boot backend from a single YAML/JSON spec. The main goal is to reduce repetitive CRUD boilerplate and keep a consistent baseline across projects.&lt;/p&gt;

&lt;p&gt;Version update: 1.0.2&lt;/p&gt;

&lt;h2&gt;
  
  
  Why I built this
&lt;/h2&gt;

&lt;p&gt;In most Spring Boot projects, the first few hours (or days) often look the same:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;CRUD layers (entity/repo/service/controller)&lt;/li&gt;
&lt;li&gt;DTO mapping / mappers&lt;/li&gt;
&lt;li&gt;consistent error responses&lt;/li&gt;
&lt;li&gt;database migrations (and keeping them in sync)&lt;/li&gt;
&lt;li&gt;Docker bits&lt;/li&gt;
&lt;li&gt;OpenAPI and resource structures&lt;/li&gt;
&lt;li&gt;tests and test data setup&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Spring CRUD Generator tries to make that “baseline” reproducible from a spec, so you can focus on domain logic instead of wasting your time and concentration writing the same code again and again.&lt;/p&gt;

&lt;h2&gt;
  
  
  What it can generate
&lt;/h2&gt;

&lt;p&gt;Depending on the configuration, it can generate:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;CRUD stack: entities, repositories, services, mappers, REST controllers&lt;/li&gt;
&lt;li&gt;Flyway migrations (incremental change detection)&lt;/li&gt;
&lt;li&gt;OpenAPI specs + optional resource generation&lt;/li&gt;
&lt;li&gt;Dockerfile + docker-compose&lt;/li&gt;
&lt;li&gt;Unit tests + test data generation (Instancio/Podam)&lt;/li&gt;
&lt;li&gt;Caching (Redis/Caffeine)&lt;/li&gt;
&lt;li&gt;GraphQL&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What improved since v1.0.0
&lt;/h2&gt;

&lt;p&gt;The initial version proved the concept, but real usage quickly exposed edge cases. Recent releases focus on stability and correctness, especially around:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;OpenAPI generation and schema handling (including optional fields)&lt;/li&gt;
&lt;li&gt;ID naming consistency across endpoints and DTOs&lt;/li&gt;
&lt;li&gt;improved equals/hashCode generation depending on whether the model is JSON-centric or a table entity&lt;/li&gt;
&lt;li&gt;stricter validation so misconfigurations fail fast&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Example spec (YAML)
&lt;/h2&gt;

&lt;p&gt;Here is a small example showing the overall idea:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;configuration&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;database&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;postgresql&lt;/span&gt;
  &lt;span class="na"&gt;migrationScripts&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
  &lt;span class="na"&gt;errorResponse&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;MINIMAL&lt;/span&gt;
  &lt;span class="na"&gt;openApi&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;apiSpec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
    &lt;span class="na"&gt;generateResources&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
  &lt;span class="na"&gt;docker&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;dockerfile&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
    &lt;span class="na"&gt;dockerCompose&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
  &lt;span class="na"&gt;tests&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;unit&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
    &lt;span class="na"&gt;dataGenerator&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;instancio&lt;/span&gt;

&lt;span class="na"&gt;entities&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Product&lt;/span&gt;
    &lt;span class="na"&gt;storageName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;product_table&lt;/span&gt;
    &lt;span class="na"&gt;audit&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;enabled&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
      &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;LocalDate&lt;/span&gt;
    &lt;span class="na"&gt;fields&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;id&lt;/span&gt;
        &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Long&lt;/span&gt;
        &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;strategy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;IDENTITY&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;name&lt;/span&gt;
        &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;String&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;tags&lt;/span&gt;
        &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;List&amp;lt;String&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Quick start
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Create your spec file, for example:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;src/main/resources/crud-generator.yml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Configure the Maven plugin (see the repository README)&lt;/li&gt;
&lt;li&gt;Run generation
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;mvn clean &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-DskipTests&lt;/span&gt; &lt;span class="nt"&gt;-Pgenerate-resources&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This should generate the backend sources and related resources based on your YAML/JSON spec.&lt;/p&gt;

&lt;h2&gt;
  
  
  Links
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Github repo:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;https://github.com/mzivkovicdev/spring-crud-generator
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Maven Central artifact:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;dev.markozivkovic:spring-crud-generator:1.0.2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Feedback welcome
&lt;/h2&gt;

&lt;p&gt;If you have a few minutes, I’d love feedback on:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the spec design (YAML/JSON structure and ergonomics)&lt;/li&gt;
&lt;li&gt;what you expect from generated “production baseline” code&lt;/li&gt;
&lt;li&gt;edge cases you’d test first&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>java</category>
      <category>springboot</category>
      <category>webdev</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Spring CRUD Generator (v1.0.0): Generate Spring Boot CRUD, Flyway, tests &amp; more from YAML/JSON</title>
      <dc:creator>Marko</dc:creator>
      <pubDate>Fri, 23 Jan 2026 15:06:11 +0000</pubDate>
      <link>https://forem.com/mzivkovicdev/spring-crud-generator-v100-generate-spring-boot-crud-flyway-tests-more-from-yamljson-28ag</link>
      <guid>https://forem.com/mzivkovicdev/spring-crud-generator-v100-generate-spring-boot-crud-flyway-tests-more-from-yamljson-28ag</guid>
      <description>&lt;p&gt;I just open-sourced &lt;strong&gt;Spring CRUD Generator (v1.0.0)&lt;/strong&gt; — a Maven plugin that generates a production-ready Spring Boot backend from a single YAML/JSON spec.&lt;/p&gt;

&lt;p&gt;The goal: &lt;strong&gt;less boilerplate&lt;/strong&gt;, consistent structure, and faster iteration.&lt;/p&gt;

&lt;h2&gt;
  
  
  What it can generate (depending on configuration)
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;CRUD stack: entities, repositories, services, mappers, REST controllers&lt;/li&gt;
&lt;li&gt;Flyway migrations (incremental change detection via state files)&lt;/li&gt;
&lt;li&gt;OpenAPI specs + optional resource generation&lt;/li&gt;
&lt;li&gt;Dockerfile + docker-compose&lt;/li&gt;
&lt;li&gt;Unit tests + test data generation (Instancio/Podam)&lt;/li&gt;
&lt;li&gt;Caching (Redis/Caffeine)&lt;/li&gt;
&lt;li&gt;GraphQL&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Maven coordinates
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;dev.markozivkovic:spring-crud-generator:1.0.0&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;GitHub: &lt;a href="https://github.com/mzivkovicdev/spring-crud-generator" rel="noopener noreferrer"&gt;https://github.com/mzivkovicdev/spring-crud-generator&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Tiny spec example
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;configuration&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;database&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;postgresql&lt;/span&gt;
  &lt;span class="na"&gt;migrationScripts&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
  &lt;span class="na"&gt;errorResponse&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;MINIMAL&lt;/span&gt;
  &lt;span class="na"&gt;openApi&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;apiSpec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
    &lt;span class="na"&gt;generateResources&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
  &lt;span class="na"&gt;docker&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;dockerfile&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
    &lt;span class="na"&gt;dockerCompose&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
  &lt;span class="na"&gt;tests&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;unit&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
    &lt;span class="na"&gt;dataGenerator&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;instancio&lt;/span&gt;

&lt;span class="na"&gt;entities&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Product&lt;/span&gt;
    &lt;span class="na"&gt;storageName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;product_table&lt;/span&gt;
    &lt;span class="na"&gt;audit&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;enabled&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
      &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;LocalDate&lt;/span&gt;
    &lt;span class="na"&gt;fields&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;id&lt;/span&gt;
        &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Long&lt;/span&gt;
        &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;strategy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;IDENTITY&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;name&lt;/span&gt;
        &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;String&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;tags&lt;/span&gt;
        &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;List&amp;lt;String&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Quick start
&lt;/h2&gt;

&lt;p&gt;Add a Maven profile and run the generator goal (see README for the full setup and configuration reference).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;mvn clean &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-Pgenerate-resources&lt;/span&gt; &lt;span class="nt"&gt;-DskipTests&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Feedback
&lt;/h2&gt;

&lt;p&gt;I'd love to hear your feedback, if you have ideas for additional features or improvements, that is highly appreciated!&lt;/p&gt;

</description>
      <category>java</category>
      <category>springboot</category>
      <category>opensource</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
