<?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>DEV Community: Deniss Sudak</title>
    <description>The latest articles on DEV Community by Deniss Sudak (@denissudak).</description>
    <link>https://dev.to/denissudak</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%2F3239880%2Fae899d41-a039-41df-b95e-bc9de4271b35.jpeg</url>
      <title>DEV Community: Deniss Sudak</title>
      <link>https://dev.to/denissudak</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/denissudak"/>
    <language>en</language>
    <item>
      <title>Applying matching algorithms to real allocation problems. Part 2</title>
      <dc:creator>Deniss Sudak</dc:creator>
      <pubDate>Mon, 09 Jun 2025 01:48:43 +0000</pubDate>
      <link>https://dev.to/denissudak/applying-matching-algorithms-to-real-allocation-problems-part-2-3ami</link>
      <guid>https://dev.to/denissudak/applying-matching-algorithms-to-real-allocation-problems-part-2-3ami</guid>
      <description>&lt;p&gt;In &lt;a href="https://dev.to/denissudak/applying-matching-algorithms-to-real-allocation-problems-part-1-24dm"&gt;Part 1&lt;/a&gt;, we discussed how to match applicants to roles. In this part, we’ll explore how to determine which roles need to be filled to complete the team. Let’s describe this problem through examples.&lt;/p&gt;

&lt;p&gt;Let’s start with a simple case. Suppose we have a job that needs two people with “skill-1.” We’ve assigned this role to one person. We still need someone with “skill-1” to complete the team.&lt;/p&gt;

&lt;p&gt;Now let’s say we have a job that requires one person with “skill-1” and one person with “skill-2.” We’ve assigned the “skill-1” role to someone who has both “skill-1” and “skill-2.” To complete the team, we obviously need someone with “skill-2,” but actually, someone with “skill-1” will do as well, as we can reassign the current applicant to the “skill-2” role.&lt;/p&gt;

&lt;p&gt;As you can imagine, in complex scenarios with multiple roles and applicants with multiple skills, we can reshuffle role assignments in many ways to accommodate a new applicant who helps complete the team.&lt;/p&gt;

&lt;p&gt;Here, we’ll discuss how to determine which applicants with which skills could join the team without replacing anyone currently on it.&lt;/p&gt;

&lt;p&gt;Suppose we have the following roles to fill:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fez02fobbvyf3cqsmx9le.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fez02fobbvyf3cqsmx9le.webp" alt="Team requirements" width="800" height="154"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And right now, we have two applicants:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frdktrnrtgzfvd55t6vnj.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frdktrnrtgzfvd55t6vnj.webp" alt="Applicant skills" width="800" height="149"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In other words, any applicant is suitable for any role.&lt;/p&gt;

&lt;p&gt;Here’s how our problem would look like in a flow network form.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fph2ktokzsszmzgcs4v5a.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fph2ktokzsszmzgcs4v5a.webp" alt="flow network representation of the problem" width="800" height="261"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now, let’s say that after running our matching algorithm, both applicant-1 and applicant-2 are assigned to the “skill-1” role. To do that, I’m running a push-relabel maximum flow algorithm. By the time it terminates, the original network will have been transformed into the following residual graph:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fp4zlja6gkwvcd3c3zgmr.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fp4zlja6gkwvcd3c3zgmr.webp" alt="residual graph" width="800" height="261"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can think of a residual graph as a network of the remaining (residual) capacity after the flow has been set. For example, since applicant-1 is assigned the “skill-1” role, there is no more flow from A-1 to S-1. However, it’s possible to “undo” this assignment by directing flow from the Sink to S-1 and from S-1 to A-1. From there, excess can flow to S-2 and then to the Sink, thus reassigning applicant-1 to the “skill-2” role.&lt;/p&gt;

&lt;p&gt;So how do we determine which applicants with which skills could join the team without replacing anyone already on it?&lt;/p&gt;

&lt;p&gt;If a team requirement needs more members than are currently assigned, then clearly we need applicants with those skills.&lt;/p&gt;

&lt;p&gt;If a team requirement is already satisfied — that is, it has the number of team members it requires (like S-1 in our example) — then we need to check whether at least one of those team members could be reassigned to another role. We do that in the following way:&lt;/p&gt;

&lt;p&gt;We add 1 to the capacity of the arc that emanates from the Source and ends at each node corresponding to team members linked to the team requirement in question. If that increases the flow, then at least one of those team members found another role (without displacing anyone), and so we can say that we need another applicant with those skills.&lt;/p&gt;

&lt;p&gt;This is like cloning applicants already assigned to a role and then checking if at least one of them can take on a different role without kicking anyone out.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0y06weksu5jh8zdwbxyg.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0y06weksu5jh8zdwbxyg.webp" alt="pseudo code" width="800" height="357"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Try it yourself
&lt;/h2&gt;

&lt;p&gt;You can experiment with this algorithm using the following repo:&lt;/p&gt;

&lt;p&gt;👉 &lt;a href="https://github.com/denissudak/applicant-job-matching" rel="noopener noreferrer"&gt;https://github.com/denissudak/applicant-job-matching&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I hope you’ll find it useful.&lt;/p&gt;

</description>
      <category>graphtheory</category>
      <category>algorithms</category>
      <category>maximumflow</category>
      <category>combinatorial</category>
    </item>
    <item>
      <title>Applying matching algorithms to real allocation problems. Part 1</title>
      <dc:creator>Deniss Sudak</dc:creator>
      <pubDate>Mon, 09 Jun 2025 01:42:06 +0000</pubDate>
      <link>https://dev.to/denissudak/applying-matching-algorithms-to-real-allocation-problems-part-1-24dm</link>
      <guid>https://dev.to/denissudak/applying-matching-algorithms-to-real-allocation-problems-part-1-24dm</guid>
      <description>&lt;h2&gt;
  
  
  The problem
&lt;/h2&gt;

&lt;p&gt;Many allocation problems can be reduced to the maximum bipartite matching: assigning workers to jobs, students to courses or residencies, tasks to available servers, and so on. This series of articles walks through a concrete example and then extends it to more advanced scenarios that you might encounter in the real world. I’ll assume you’re familiar with graphs and flow networks. If not, you can always learn these subjects — there is a lot of excellent material out there.&lt;/p&gt;

&lt;p&gt;For everything I talk about here there is working code you can download and play with.&lt;/p&gt;

&lt;h2&gt;
  
  
  Example: matching applicants to jobs
&lt;/h2&gt;

&lt;p&gt;Suppose we have a single job with these requirements:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3l2xl62itz5rrgzlpd95.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3l2xl62itz5rrgzlpd95.webp" alt="Team requirements" width="800" height="183"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And three applicants whose skills look like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fx6l12yvo8atclrcyepwi.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fx6l12yvo8atclrcyepwi.webp" alt="Applicant skills" width="800" height="186"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Our goal is to assign applicants to roles so that the maximum number of positions is filled.&lt;/p&gt;

&lt;p&gt;If, for a moment, we ignore how many people each role needs, the problem can be modelled as a bipartite graph:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fq64j4kmhk1topezq3fx1.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fq64j4kmhk1topezq3fx1.webp" alt="bipartite graph representation of the problem" width="411" height="441"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Nodes on the left represent the applicants. Nodes on the right represent the roles. The edges that connect them signify that an applicant has the skills required for the role. For example A-1 has skill-1 and skill-2 and that’s why they are connected to S-1 and S-2.&lt;/p&gt;

&lt;p&gt;There are numerous algorithms that find the maximum matching in bipartite graphs. Some of them do it via flow networks — the problem is reduced to finding a maximum flow in a network and then the flow is converted back into matching. For our problem I prefer the flow network approach as it allows us to easily encode that we need 2 people with skill-2 and 2 more people with skill-3. Here’s how our problem would look like in a flow network form.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3zmlfm4uq9vls5jksznb.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3zmlfm4uq9vls5jksznb.webp" alt="flow network representation of the problem" width="800" height="356"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The new nodes are the &lt;em&gt;source&lt;/em&gt; and the &lt;em&gt;sink&lt;/em&gt;. The flow emanates from the source and needs to find its way to the sink via directed edges without exceeding the capacity of any of the edges.&lt;/p&gt;

&lt;p&gt;The edges that go from the source to the nodes that represent applicants all have a capacity of one. This represents the fact that we have only one of each of the applicants. Edges that connect applicants to the role nodes also have a capacity of one — each applicant can only do one role. If applicant-1 is assigned the role that requires skill-1 then that’s it, they can’t be assigned anything else. The capacities of edges that connect role nodes to the sink represent the number of people required for that role. For example, S-2 needs two people and so has the capacity to take the flow from both A-1 and A-2.&lt;/p&gt;

&lt;p&gt;Once we have the flow network the goal is to find the path the flow should take in order to reach its maximum. Just as there could be several maximum matchings in a bipartite graph, there could be several maximum flows in the network. Here’s one of them:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Foaagzt9p79orz258rm0c.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Foaagzt9p79orz258rm0c.webp" alt="Maximum flow" width="800" height="356"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here’s another:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frux0v0niiy5ve26ry4lu.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frux0v0niiy5ve26ry4lu.webp" alt="Maximum flow" width="800" height="356"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In both cases the flow is 3, meaning that all three applicants are assigned roles. It’s easy to convert the flow back to role assignments. Using the first flow: applicant-1 is assigned the role that requires skill-1; applicant-2 is assigned skill-3; applicant-3 is assigned skill-2.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try it yourself
&lt;/h2&gt;

&lt;p&gt;If you want to explore the examples above and experiment with matching applicants to jobs, you can download the code here: &lt;a href="https://github.com/denissudak/applicant-job-matching" rel="noopener noreferrer"&gt;https://github.com/denissudak/applicant-job-matching&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Continue to &lt;a href="https://dev.to/denissudak/applying-matching-algorithms-to-real-allocation-problems-part-2-3ami"&gt;Part 2&lt;/a&gt; that talks about how to calculate what roles are still in demand (what skills are still required to complete the team). 🙂&lt;/p&gt;

</description>
      <category>graphtheory</category>
      <category>matchingalgorithm</category>
      <category>maximumflow</category>
      <category>networkflows</category>
    </item>
    <item>
      <title>How to keep unread notifications relevant</title>
      <dc:creator>Deniss Sudak</dc:creator>
      <pubDate>Mon, 02 Jun 2025 20:42:50 +0000</pubDate>
      <link>https://dev.to/denissudak/how-to-keep-unread-notifications-relevant-48b9</link>
      <guid>https://dev.to/denissudak/how-to-keep-unread-notifications-relevant-48b9</guid>
      <description>&lt;p&gt;You’ve probably puzzled over this at some point in your career. Don’t worry — the answer is here.&lt;/p&gt;

&lt;p&gt;First of all, what do I mean by keeping unread notifications relevant? What’s the problem? Like a lot of things, it’s easier to explain with an example.&lt;/p&gt;

&lt;p&gt;Let’s say we have a system that helps you find people for upcoming job shifts. It sends a notification to someone asking if they want a shift on Saturday from 12 pm to 3 pm at a given address. A few people respond “yes,” you pick someone, and that person gets notified that they’ve got the gig. If the time of the shift changes or it gets cancelled altogether, the system sends them another notification.&lt;/p&gt;

&lt;p&gt;Now let’s zoom in. The job is offered. That notification says something like:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;New job on 18th of April, 12pm — 3pm, 48 Pirrama Rd, Pyrmont NSW 2009&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;They get a ping that there’s a new notification. They’re out and about and haven’t read it yet. In the meantime, you realise the shift is longer and update the job in the system. It issues another notification:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;The job has changed to 18th of April, 12pm — 5pm, 48 Pirrama Rd, Pyrmont NSW 2009&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;When they finally check their notifications, ideally we’d like them to see a single notification:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;New job on 18th of April, 12pm — 5pm at 48 Pirrama Rd, Pyrmont NSW 2009&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Now let’s say they’ve got the job, and a few days later the details change again:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;The job has changed to 18th of April, 12pm — 5pm, 14 Vine St, Redfern NSW 2016&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Just like before, they’re out and haven’t checked their phone. Then you realise the job is cancelled. The system sends one more notification:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;The job is cancelled.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Again, when they check their notifications, we’d like them to see only the cancellation — the previous job updates are no longer relevant once the job is cancelled.&lt;/p&gt;

&lt;p&gt;There could be many more notifications, with various ways they affect one another. Here’s how to structure your code in a way that’s robust and easy to expand.&lt;/p&gt;

&lt;h2&gt;
  
  
  Structure
&lt;/h2&gt;

&lt;p&gt;We have two main parts: a set of &lt;strong&gt;existing notifications&lt;/strong&gt; and a &lt;strong&gt;new notification&lt;/strong&gt; that gets added to the set. It’ll either update some of the existing notifications or be added as a new one.&lt;/p&gt;

&lt;p&gt;Going back to our example, let’s say our set of existing notifications contains a single job notification:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;New job on 18th of April, 12pm — 3pm, 48 Pirrama Rd, Pyrmont NSW 2009&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The new job change notification gets added to the set:&lt;/p&gt;

&lt;p&gt;The job has changed to 18th of April, &lt;strong&gt;12pm — 5pm&lt;/strong&gt;, 48 Pirrama Rd, Pyrmont NSW 2009&lt;/p&gt;

&lt;p&gt;As a result, we expect the set to contain just one notification:&lt;/p&gt;

&lt;p&gt;New job on 18th of April, &lt;strong&gt;12pm — 5pm&lt;/strong&gt; at 48 Pirrama Rd, Pyrmont NSW 2009&lt;/p&gt;

&lt;p&gt;We loop through existing notifications and “update” them one by one with the new notification. In that process, we check whether both the new and old notifications are still relevant and act accordingly:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjoucxi52dbuh48cz8gu7.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjoucxi52dbuh48cz8gu7.webp" alt="Image description" width="800" height="445"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Example
&lt;/h2&gt;

&lt;p&gt;What’s a technical article without a class diagram?&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5qwx8hurv43px4hun7yw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5qwx8hurv43px4hun7yw.png" alt="Image description" width="725" height="647"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here &lt;strong&gt;NotificationSet&lt;/strong&gt; represents the set of existing notifications that we want to update with the new notification. This new notification is passed to the add method as a parameter of type &lt;strong&gt;NotificationData&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Each existing notification has its own update logic that is represented by &lt;strong&gt;ExistingNotificationUpdate&lt;/strong&gt;. It interacts with &lt;strong&gt;NewNotificationAddition&lt;/strong&gt; — the logic of adding the new notification to the set. After all these interactions it determines if this new notification isRelevant(). Similarly the ExistingNotificationUpdate determines if it should be deleted via isDeleted() method.&lt;/p&gt;

&lt;h2&gt;
  
  
  Java implementation
&lt;/h2&gt;

&lt;p&gt;Here’s Java implementation of the above pseudo-code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;NotificationData&lt;/span&gt; &lt;span class="n"&gt;newNotificationData&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;checkNotNull&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;newNotificationData&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

    &lt;span class="nc"&gt;NewNotificationAddition&lt;/span&gt; &lt;span class="n"&gt;newNotificationAddition&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;newNotificationData&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;createNewNotificationAddition&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Notification&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;newHashSet&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;notifications&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;ExistingNotificationUpdate&lt;/span&gt; &lt;span class="n"&gt;existingNotificationUpdate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;notificationUpdateFactory&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;createNotificationUpdate&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;newNotificationAddition&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;call&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;existingNotificationUpdate&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;existingNotificationUpdate&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;isDeleted&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;notifications&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;remove&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;newNotificationAddition&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;isRelevant&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;notifications&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;add&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;notificationFactory&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;newNotification&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;newNotificationData&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I’ve written a working example that demonstrates this pattern: &lt;a href="https://github.com/denissudak/unread-notifications-update" rel="noopener noreferrer"&gt;https://github.com/denissudak/unread-notifications-update&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Even if you don’t work with Java, I’d still recommend checking it out as it communicates the idea through working code.&lt;/p&gt;

&lt;p&gt;I hope you find it useful. Enjoy!&lt;/p&gt;

</description>
      <category>java</category>
      <category>systemdesign</category>
      <category>ux</category>
      <category>architecture</category>
    </item>
    <item>
      <title>How to build multi-step message processing</title>
      <dc:creator>Deniss Sudak</dc:creator>
      <pubDate>Mon, 02 Jun 2025 20:27:44 +0000</pubDate>
      <link>https://dev.to/denissudak/how-to-build-multi-step-message-processing-pe5</link>
      <guid>https://dev.to/denissudak/how-to-build-multi-step-message-processing-pe5</guid>
      <description>&lt;p&gt;Let’s say you have a service that, in response to some event, performs a series of operations that can’t be wrapped into an atomic transaction. For example, this service might integrate with an accounting system and, in response to a sale event, create an invoice (&lt;strong&gt;Step 1&lt;/strong&gt;) and send that invoice to a customer (&lt;strong&gt;Step 2&lt;/strong&gt;). If either of these two steps fails, the entire sale event processing should be retried. However, if &lt;strong&gt;Step 1&lt;/strong&gt; succeeds, but emailing the invoice fails, we obviously should retry only the email step and not create a duplicate invoice.&lt;/p&gt;

&lt;p&gt;The idea is simple: persist the status of each processing step (e.g. invoice creation and emailing) in a database, and during a retry, resume from the failed step.&lt;/p&gt;

&lt;p&gt;These statuses will be fetched from the database using an ID derived from the received message. A status can have one of the three values:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;PROCESSING&lt;/li&gt;
&lt;li&gt;SUCCESS&lt;/li&gt;
&lt;li&gt;TRY_AGAIN&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;SUCCESS&lt;/strong&gt; means that the step has completed successfully and not to be executed again.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;TRY_AGAIN&lt;/strong&gt; means that the step has failed in a way that is safe to retry. For example our accounting system returned 4xx error, indicating that the action wasn’t successful.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;PROCESSING&lt;/strong&gt; is set temporarily while the step is in progress. If it succeeds, we set it to SUCCESS. If it fails in a way where it’s unclear whether to retry (e.g. 5xx error), the status remains PROCESSING. In this case, the entire workflow is locked and cannot proceed until a human (or automation) determines what happened and updates the state.&lt;/p&gt;

&lt;h2&gt;
  
  
  Processing context
&lt;/h2&gt;

&lt;p&gt;Every step may produce data that is required by the next step. For example, sending the invoice requires an invoice ID, which is generated by the external accounting system in the first step.&lt;/p&gt;

&lt;p&gt;Data produced by the successful steps (like the invoice ID) will be stored in the &lt;strong&gt;message processing context.&lt;/strong&gt; This way, when the message is retried, all the data is already there and ready to use.&lt;/p&gt;

&lt;p&gt;Here’s the example of the event processing record:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"eventId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"sale-1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"createdInvoiceId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"abc-xyz-123"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"stepProcessingStatuses"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"stepCode"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"create-new-invoice"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"status"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"SUCCESS"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"stepCode"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"email-invoice"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"status"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"TRY_AGAIN"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"locked"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, “sale-1” is the ID of the event that is being processed. This is the ID used to look up the record when the event is retried. If the “email-invoice” step fails, during the second attempt this record will be fetched. I’ll show that “create-new-invoice” was successful and should be skipped. The “email-invoice” step will then reuse the previously stored “createdInvoiceId”.&lt;/p&gt;

&lt;h2&gt;
  
  
  What’s “locked”?
&lt;/h2&gt;

&lt;p&gt;To ensure that the same step isn’t executed more than once, we must prevent multiple workers from processing the same message simultaneously.&lt;/p&gt;

&lt;p&gt;This might not be an issue depending on your message queue. For example, &lt;strong&gt;AWS SQS FIFO&lt;/strong&gt; queues have exactly-once delivery guarantees.&lt;/p&gt;

&lt;p&gt;It’s less critical if duplicate execution isn’t a big deal. For instance, in a multi-step AI pipeline where each step processes data from the previous one, concurrent processing might just result in some extra API usage — not the end of the world.&lt;/p&gt;

&lt;p&gt;However if your queue comes with at-least-once delivery guarantee (like standard AWS SQS), and you don’t want to create duplicate invoices then having a way to lock an event processing from other workers is essential.&lt;/p&gt;

&lt;p&gt;On a high level this simply means that before processing an event, a worker has to successfully acquire a lock and release the lock after it’s done with the event. If any other worker picks up the message while it’s locked then it would ignore the event.&lt;/p&gt;

&lt;p&gt;Pick a database that guarantees atomic updates, so only one worker can successfully acquire the lock at a time.&lt;/p&gt;

&lt;h2&gt;
  
  
  Code example
&lt;/h2&gt;

&lt;p&gt;I’ve written a working example that demonstrates this pattern using Java Spring, AWS SQS and DynamoDB: &lt;a href="https://github.com/denissudak/multi-step-event-processing" rel="noopener noreferrer"&gt;https://github.com/denissudak/multi-step-event-processing&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;DynamoDB is a good choice for this use case.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Expressions.OperatorsAndFunctions.html" rel="noopener noreferrer"&gt;Condition expressions&lt;/a&gt; support the locking functionality that we need.&lt;/li&gt;
&lt;li&gt;Flexible schema allows any shape of processing context data (like “createdInvoiceId”).&lt;/li&gt;
&lt;li&gt;You can use a single table to store processing records for multiple event types.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Even if you don’t work with Java, I would still suggest checking it out as it communicates the idea via working code.&lt;/p&gt;

&lt;p&gt;I hope you find it useful. Enjoy!&lt;/p&gt;

</description>
      <category>eventdriven</category>
      <category>distributedsystems</category>
      <category>architecture</category>
    </item>
    <item>
      <title>Java proxy for overlapping interfaces</title>
      <dc:creator>Deniss Sudak</dc:creator>
      <pubDate>Mon, 02 Jun 2025 18:59:31 +0000</pubDate>
      <link>https://dev.to/denissudak/java-proxy-for-overlapping-interfaces-19p7</link>
      <guid>https://dev.to/denissudak/java-proxy-for-overlapping-interfaces-19p7</guid>
      <description>&lt;p&gt;If you are writing in Java and need to convert a DTO (data transfer object) to JSON before sending it out, there are libraries that will do this task for you. &lt;a href="https://github.com/FasterXML/jackson" rel="noopener noreferrer"&gt;Jackson&lt;/a&gt; is one of them. It’ll use Java reflection to look for getters to figure out what data to write to JSON.&lt;/p&gt;

&lt;p&gt;Let’s say you have a few of these DTOs and some parts of them overlap, that is they have the same fields in common. You don’t need many overlapping DTOs before you end-up with code duplication that you can’t overcome with inheritance alone. Does it matter? DTOs are just lightweight data containers. There is no business logic in them. What duplication are we talking about?&lt;/p&gt;

&lt;p&gt;Fine. But a DTO doesn’t have to be just a POJO when it has the potential to be so much more :) For example, it can represent your integration with an accounting system:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;AccountingDTO&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
   &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;LineItem&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;getProfitLoss&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
   &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;ListItem&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;getBalanceSheet&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
   &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Invoice&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;getInvoices&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Imagine that these getters fetch data from Xero.&lt;/p&gt;

&lt;p&gt;Now let’s say you only need to P&amp;amp;L and balance sheet converted to JSON to serve the first request. Another request requires P&amp;amp;L and invoices, and the third needs only invoices and, again, the balance sheet. Giving the entire AccountingDTO to Jackson will serialise everything making unnecessary requests to that accounting system as well as sending back JSON larger than is needed. If you split into 3 DTOs then, for example, the getProfitLoss method would have to appear in two of them and that’s duplication.&lt;/p&gt;

&lt;p&gt;The solution I came up with is to create three interfaces that list only the getters required for their corresponding requests while keeping all the business logic in AccountingDTO.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnmjf89qqqftfht9hnxlq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnmjf89qqqftfht9hnxlq.png" alt="Class diagram" width="800" height="264"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For each of these interfaces, create what I call a super‑interface proxy — a proxy instance that exposes only the required subset of methods, while every call is passed through to the full AccountingDTO implementation. Giving one of these proxies to Jackson generates JSON that contains only what the interface (and not the underlying implementation) specifies.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;SuperInterfaceProxyFactory&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Super&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="no"&gt;T&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Super&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;Class&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Super&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;superClass&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;SuperInterfaceProxyFactory&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Class&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Super&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;superClass&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;superClass&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;requireNonNull&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;superClass&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;Super&lt;/span&gt; &lt;span class="nf"&gt;newProxy&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="no"&gt;T&lt;/span&gt; &lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;checkNotNull&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Super&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="nc"&gt;Proxy&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;newProxyInstance&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
                &lt;span class="n"&gt;superClass&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getClassLoader&lt;/span&gt;&lt;span class="o"&gt;(),&lt;/span&gt;
                &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Class&lt;/span&gt;&lt;span class="o"&gt;[]{&lt;/span&gt;&lt;span class="n"&gt;superClass&lt;/span&gt;&lt;span class="o"&gt;},&lt;/span&gt;
                &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;PassThroughInvocationHandler&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;PassThroughInvocationHandler&lt;/span&gt; &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="nc"&gt;InvocationHandler&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;Object&lt;/span&gt; &lt;span class="n"&gt;target&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

        &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nf"&gt;PassThroughInvocationHandler&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Object&lt;/span&gt; &lt;span class="n"&gt;target&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;target&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;requireNonNull&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;target&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;

        &lt;span class="nd"&gt;@Override&lt;/span&gt;
        &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;Object&lt;/span&gt; &lt;span class="nf"&gt;invoke&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Object&lt;/span&gt; &lt;span class="n"&gt;proxy&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Method&lt;/span&gt; &lt;span class="n"&gt;method&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Object&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="kd"&gt;throws&lt;/span&gt; &lt;span class="nc"&gt;Throwable&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;method&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;invoke&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;target&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here your &lt;code&gt;Super&lt;/code&gt; could be AccountingDTO1 interface, and &lt;code&gt;T&lt;/code&gt; the implementation that contains all the methods. The object&lt;br&gt;
returned by newProxy will generate JSON that you need. Have a look at the code example: &lt;a href="https://github.com/denissudak/java-super-interface-proxy" rel="noopener noreferrer"&gt;https://github.com/denissudak/java-super-interface-proxy&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I hope you find it useful. Enjoy!&lt;/p&gt;

</description>
      <category>java</category>
      <category>json</category>
      <category>designpatterns</category>
      <category>interfacesegregation</category>
    </item>
  </channel>
</rss>
