<?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: christoph-sens</title>
    <description>The latest articles on DEV Community by christoph-sens (@christophsens).</description>
    <link>https://dev.to/christophsens</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.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4144605%2F41c75140-9001-42b5-ba91-5c0ee818a68d.png</url>
      <title>DEV Community: christoph-sens</title>
      <link>https://dev.to/christophsens</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/christophsens"/>
    <language>en</language>
    <item>
      <title>Large SQS and SNS messages in Kotlin: the extended client pattern without Java baggage</title>
      <dc:creator>christoph-sens</dc:creator>
      <pubDate>Sat, 26 Sep 2026 16:39:40 +0000</pubDate>
      <link>https://dev.to/christophsens/large-sqs-and-sns-messages-in-kotlin-the-extended-client-pattern-without-java-baggage-l9d</link>
      <guid>https://dev.to/christophsens/large-sqs-and-sns-messages-in-kotlin-the-extended-client-pattern-without-java-baggage-l9d</guid>
      <description>&lt;p&gt;Every SQS queue and SNS topic has a message size limit. When a payload is larger, the usual answer is the &lt;em&gt;claim check&lt;/em&gt; pattern: put the payload in S3, send a small pointer instead, and resolve the pointer on the receiving side. AWS ships this pattern as two Java libraries, &lt;a href="https://github.com/awslabs/amazon-sqs-java-extended-client-lib" rel="noopener noreferrer"&gt;amazon-sqs-java-extended-client-lib&lt;/a&gt;and &lt;a href="https://github.com/awslabs/amazon-sns-java-extended-client-lib" rel="noopener noreferrer"&gt;amazon-sns-java-extended-client-lib&lt;/a&gt;, both built on &lt;a href="https://github.com/awslabs/payload-offloading-java-common-lib-for-aws" rel="noopener noreferrer"&gt;payload-offloading-java-common-lib-for-aws&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If your service is written in Kotlin on &lt;a href="https://github.com/awslabs/aws-sdk-kotlin" rel="noopener noreferrer"&gt;aws-sdk-kotlin&lt;/a&gt;,&lt;br&gt;
those libraries don't fit: they wrap the AWS SDK for Java v2 clients, not the Kotlin ones. So I&lt;br&gt;
ported them. The result is three small libraries on Maven Central:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/christoph-sens/s3overflow" rel="noopener noreferrer"&gt;s3overflow&lt;/a&gt;: the payload store (S3 upload, pointer, download, delete)&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/christoph-sens/sqsoverflow" rel="noopener noreferrer"&gt;sqsoverflow&lt;/a&gt;: an &lt;code&gt;SqsClient&lt;/code&gt; that offloads large message bodies&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/christoph-sens/snsoverflow" rel="noopener noreferrer"&gt;snsoverflow&lt;/a&gt;: an &lt;code&gt;SnsClient&lt;/code&gt; that offloads large message bodies&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This post covers why the Java libraries are a liability today, how the ports work, and what you&lt;br&gt;
need to know before migrating.&lt;/p&gt;
&lt;h2&gt;
  
  
  Where the Java libraries stand today
&lt;/h2&gt;

&lt;p&gt;The extended clients do their job, but their foundation has aged:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Old dependencies with known advisories.&lt;/strong&gt; Both clients depend on &lt;code&gt;payloadoffloading-common&lt;/code&gt; 2.2.0, whose last release was in March 2024. It pins &lt;code&gt;jackson-databind&lt;/code&gt; 2.15.2 and &lt;code&gt;jackson-core&lt;/code&gt; 2.16.0. As of September 2026, the GitHub Advisory Database lists seven advisories affecting exactly these versions, three of them rated high, among them bypasses of Jackson's polymorphic type validation and a denial-of-service issue in the async parser. Even the latest SQS client release (2.1.3, July 2026) still pulls in these versions  through the common library.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Java 8 bytecode and a pre-coroutine design.&lt;/strong&gt; 
All three libraries compile for Java 8 and keep separate sync and async client classes with largely duplicated pass-through code.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Slow release cadence.&lt;/strong&gt; 
The SNS client's latest release (2.1.0) is from March 2024, the common library's from the same month.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To be fair: whether an advisory is exploitable depends on how Jackson is used, and the extended clients only (de)serialize a small pointer object. You can also override the Jackson versions in your own build. But every dependency scanner flags these versions, someone has to triage the findings again and again, and forcing newer Jackson versions under a library that was never tested against them is its own risk. Removing Jackson from this code path makes the question disappear.&lt;/p&gt;
&lt;h2&gt;
  
  
  What the size limits are today
&lt;/h2&gt;

&lt;p&gt;The limits moved recently, which changes when offloading is needed at all:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;SQS&lt;/strong&gt; accepts messages up to &lt;strong&gt;1 MiB&lt;/strong&gt; (body plus attributes). Until August 2025 the limit was 256 KiB.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;SNS&lt;/strong&gt; accepts &lt;strong&gt;256 KiB&lt;/strong&gt; by default. Since September 2026 a topic can accept up to &lt;strong&gt;1 MiB&lt;/strong&gt; when you raise its &lt;code&gt;MaximumMessageSize&lt;/code&gt; attribute.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;sqsoverflow therefore offloads at 1 MiB by default, snsoverflow at 256 KiB. Both are configurable&lt;br&gt;
through &lt;code&gt;payloadSizeThreshold&lt;/code&gt;.&lt;/p&gt;
&lt;h2&gt;
  
  
  Usage
&lt;/h2&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="nf"&gt;dependencies&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;implementation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"com.christoph-sens:sqsoverflow:1.1.0"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;s3Client&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;S3Client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fromEnvironment&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;region&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"eu-central-1"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;sqsClient&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;SqsClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fromEnvironment&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;region&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"eu-central-1"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;client&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;SqsExtendedClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;sqsClient&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nc"&gt;SqsExtendedClientConfig&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;payloadStore&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;S3BackedPayloadStore&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s3Client&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;bucketName&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"my-payload-bucket"&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sendMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;SendMessageRequest&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;queueUrl&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;myQueueUrl&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;messageBody&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;largePayload&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;

&lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;messages&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;receiveMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;ReceiveMessageRequest&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;queueUrl&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;myQueueUrl&lt;/span&gt; &lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="n"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;orEmpty&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;process&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// the original payload, already resolved from S3&lt;/span&gt;
    &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;deleteMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;DeleteMessageRequest&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;queueUrl&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;myQueueUrl&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;receiptHandle&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;receiptHandle&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;code&gt;SqsExtendedClient&lt;/code&gt; &lt;em&gt;is&lt;/em&gt; an &lt;code&gt;SqsClient&lt;/code&gt;, so you can pass it anywhere a plain client is expected.&lt;br&gt;
Messages under the threshold go straight to SQS. Larger ones are written to S3, and SQS only carries&lt;br&gt;
a small JSON pointer plus the &lt;code&gt;ExtendedPayloadSize&lt;/code&gt; message attribute. On receive, the client fetches the payload and hands you the original body. On delete, it removes the S3 object as well (&lt;code&gt;cleanupS3Payload&lt;/code&gt;, on by default).&lt;/p&gt;

&lt;p&gt;snsoverflow works the same way for &lt;code&gt;publish&lt;/code&gt; and &lt;code&gt;publishBatch&lt;/code&gt;. SNS has no receive side, so the&lt;br&gt;
subscriber resolves the pointer: for an SNS topic that fans out to an SQS queue with raw message delivery, that's sqsoverflow's &lt;code&gt;SqsExtendedClient&lt;/code&gt;.&lt;/p&gt;
&lt;h2&gt;
  
  
  Why a port instead of a wrapper around the Java library
&lt;/h2&gt;
&lt;h3&gt;
  
  
  One suspend API instead of sync and async classes
&lt;/h3&gt;

&lt;p&gt;The Java originals come in two flavors each, for example &lt;code&gt;AmazonSQSExtendedClient&lt;/code&gt; for &lt;code&gt;SqsClient&lt;/code&gt; and &lt;code&gt;AmazonSQSExtendedAsyncClient&lt;/code&gt; for &lt;code&gt;SqsAsyncClient&lt;/code&gt;. aws-sdk-kotlin clients are &lt;code&gt;suspend&lt;/code&gt;-based from the start, so one class covers both cases and fits naturally into coroutine code.&lt;/p&gt;
&lt;h3&gt;
  
  
  Interface delegation replaces a thousand lines of pass-through code
&lt;/h3&gt;

&lt;p&gt;Most of the SQS interface has nothing to do with payload offloading: &lt;code&gt;createQueue&lt;/code&gt;, &lt;code&gt;listQueues&lt;/code&gt;, &lt;code&gt;tagQueue&lt;/code&gt; and dozens more. The Java library forwards each of these by hand in a base class of roughly 1,150 lines. Kotlin's interface delegation does this in one line:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;SqsExtendedClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;sqsClient&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;SqsClient&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;clientConfig&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;SqsExtendedClientConfig&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;SqsClient&lt;/span&gt; &lt;span class="k"&gt;by&lt;/span&gt; &lt;span class="nf"&gt;sqsClient&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="k"&gt;suspend&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;sendMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;SendMessageRequest&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nc"&gt;SendMessageResponse&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="cm"&gt;/* offload if needed */&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="c1"&gt;// ... only the methods with real offload logic are overridden&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;sqsoverflow overrides eight methods: &lt;code&gt;sendMessage&lt;/code&gt;, &lt;code&gt;sendMessageBatch&lt;/code&gt;, &lt;code&gt;receiveMessage&lt;/code&gt;,&lt;br&gt;
&lt;code&gt;deleteMessage&lt;/code&gt;, &lt;code&gt;deleteMessageBatch&lt;/code&gt;, &lt;code&gt;changeMessageVisibility&lt;/code&gt;, &lt;code&gt;changeMessageVisibilityBatch&lt;/code&gt; and&lt;br&gt;
&lt;code&gt;purgeQueue&lt;/code&gt;. snsoverflow overrides two: &lt;code&gt;publish&lt;/code&gt; and &lt;code&gt;publishBatch&lt;/code&gt;. Everything else is delegated&lt;br&gt;
to the wrapped client. All three libraries together are about 730 lines of Kotlin, license headers&lt;br&gt;
included.&lt;/p&gt;
&lt;h3&gt;
  
  
  No Jackson dependency
&lt;/h3&gt;

&lt;p&gt;The Java libraries serialize the S3 pointer with Jackson. The ports use kotlinx.serialization, so nothing in their runtime classpath is Jackson, and the advisories described above do not apply to them. Fewer transitive dependencies means fewer libraries to keep patched. Dependabot keeps the&lt;br&gt;
remaining dependencies current, and CodeQL and dependency review run on every pull request in all&lt;br&gt;
three repositories.&lt;/p&gt;
&lt;h3&gt;
  
  
  Less configuration surface
&lt;/h3&gt;

&lt;p&gt;The original configuration classes carry options for client-side encryption strategies and canned ACLs. The ports take a &lt;code&gt;PayloadStore&lt;/code&gt; and a handful of behavior flags (&lt;code&gt;payloadSizeThreshold&lt;/code&gt;, &lt;code&gt;alwaysThroughS3&lt;/code&gt;, &lt;code&gt;cleanupS3Payload&lt;/code&gt;, &lt;code&gt;ignorePayloadNotFound&lt;/code&gt;, &lt;code&gt;s3KeyPrefix&lt;/code&gt;). Encryption is configured where it belongs: on the bucket, with SSE-S3 or SSE-KMS.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;publishBatch&lt;/code&gt; in snsoverflow is offload-aware as well. The Java SNS library predates the SNS &lt;code&gt;PublishBatch&lt;/code&gt; API and only handles &lt;code&gt;publish&lt;/code&gt;.&lt;/p&gt;
&lt;h2&gt;
  
  
  Migrating from the Java libraries
&lt;/h2&gt;

&lt;p&gt;The important caveat first: &lt;strong&gt;the ports are not wire-compatible with the Java libraries.&lt;/strong&gt; The pointer JSON and the receipt-handle format differ. A message sent by the Java extended client cannot be resolved by sqsoverflow, and vice versa. Switch all producers and consumers of a queue at the&lt;br&gt;
same time, or drain the queue first.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;ExtendedPayloadSize&lt;/code&gt; attribute name is the same, so SNS-to-SQS fan-out works between snsoverflow and sqsoverflow.&lt;/p&gt;

&lt;p&gt;Before (Java):&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="nc"&gt;ExtendedClientConfiguration&lt;/span&gt; &lt;span class="n"&gt;config&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;ExtendedClientConfiguration&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;withPayloadSupportEnabled&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s3Client&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"my-payload-bucket"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="nc"&gt;SqsClient&lt;/span&gt; &lt;span class="n"&gt;client&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;AmazonSQSExtendedClient&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;SqsClient&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;builder&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="o"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After (Kotlin):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;client&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;SqsExtendedClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nc"&gt;SqsClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fromEnvironment&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="nc"&gt;SqsExtendedClientConfig&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;payloadStore&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;S3BackedPayloadStore&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s3Client&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;bucketName&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"my-payload-bucket"&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Options without an equivalent:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Java option&lt;/th&gt;
&lt;th&gt;In the ports&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Client-side encryption (&lt;code&gt;ServerSideEncryptionStrategy&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;Configure SSE-S3 or SSE-KMS on the bucket&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ObjectCannedACL&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Use bucket policies&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SNS per-message &lt;code&gt;"S3Key"&lt;/code&gt; attribute&lt;/td&gt;
&lt;td&gt;Use &lt;code&gt;s3KeyPrefix&lt;/code&gt; in the config&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Legacy &lt;code&gt;SQSLargePayloadSize&lt;/code&gt; attribute name&lt;/td&gt;
&lt;td&gt;Always &lt;code&gt;ExtendedPayloadSize&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Verifying what you download
&lt;/h2&gt;

&lt;p&gt;Every release is built and published by a GitHub Actions workflow. The jars, POM and Gradle module metadata on Maven Central carry a signed &lt;a href="https://docs.github.com/en/actions/security-for-github-actions/using-artifact-attestations" rel="noopener noreferrer"&gt;build provenance attestation&lt;/a&gt;that ties each file to the repository, the workflow and the tagged commit it was built from. You can check a downloaded jar with the GitHub CLI:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gh attestation verify sqsoverflow-1.1.0.jar &lt;span class="nt"&gt;--repo&lt;/span&gt; christoph-sens/sqsoverflow
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Licensing
&lt;/h2&gt;

&lt;p&gt;sqsoverflow and snsoverflow are derivative works of the AWS libraries under Apache-2.0, with per-file attribution and a NOTICE file listing what was changed. s3overflow is an independent reimplementation that takes no code from &lt;code&gt;payload-offloading-java-common-lib-for-aws&lt;/code&gt;.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;s3overflow: &lt;a href="https://github.com/christoph-sens/s3overflow" rel="noopener noreferrer"&gt;https://github.com/christoph-sens/s3overflow&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;sqsoverflow: &lt;a href="https://github.com/christoph-sens/sqsoverflow" rel="noopener noreferrer"&gt;https://github.com/christoph-sens/sqsoverflow&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;snsoverflow: &lt;a href="https://github.com/christoph-sens/snsoverflow" rel="noopener noreferrer"&gt;https://github.com/christoph-sens/snsoverflow&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Issues and pull requests are welcome. If you run into a case the libraries don't cover yet, such as another AWS service that could use the same pattern, open an issue.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;I'm a freelance developer and consultant working on Kotlin, Java and AWS. The story of how these libraries came about is on my website (in German):&lt;br&gt;
&lt;a href="https://www.christoph-sens.com/post/der-scan-befund-der-nie-verschwindet-wie-eine-ki-drei-aws-legacy-bibliotheken-an-einem-nachmittag" rel="noopener noreferrer"&gt;1150 Zeilen Legacy, eine Zeile Kotlin&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>kotlin</category>
      <category>aws</category>
      <category>opensource</category>
      <category>java</category>
    </item>
  </channel>
</rss>
