Resolving GZIP Compression Issues in Apigee Java Callout
The [B@709ec03e output indicates you have a byte array, which is good, but there are several common issues that cause gzip failures in Apigee. Here’s how to resolve them:
Common Issues & Solutions
1. Incorrect Content-Type Header
Content-Type: application/gzip (NOT application/zip)
2. Message Assignment in Java Callout
Your Java callout must properly write the compressed bytes. Here’s the correct implementation:
java
import com.apigee.flow.execution.ExecutionContext;
import com.apigee.flow.execution.ExecutionResult;
import com.apigee.flow.execution.spi.Execution;
import com.apigee.flow.message.MessageContext;
import java.io.ByteArrayOutputStream;
import java.util.zip.GZIPOutputStream;
public class GzipCompressor implements Execution {
public ExecutionResult execute(MessageContext messageContext,
ExecutionContext executionContext) {
try {
// Read input XML
String inputPayload = messageContext.getVariable("inputPayload");
// Compress
ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
GZIPOutputStream gzipStream = new GZIPOutputStream(byteStream);
gzipStream.write(inputPayload.getBytes("UTF-8"));
gzipStream.close(); // CRITICAL: Must close to finalize GZIP format
byte[] compressedData = byteStream.toByteArray();
// Set as message content
messageContext.getMessage().setContent(compressedData);
// Set headers
messageContext.setVariable("request.header.Content-Type", "application/gzip");
messageContext.setVariable("request.header.Content-Encoding", "gzip");
return ExecutionResult.SUCCESS;
} catch (Exception e) {
messageContext.setVariable("gzip.error", e.getMessage());
return ExecutionResult.ABORT;
}
}
}
3. Critical: Close the GZIPOutputStream
The most common mistake is not closing the GZIPOutputStream:
java
gzipStream.close(); // Writes GZIP trailer - MUST be called
Without closing, the GZIP format is incomplete and invalid.
4. Set Both Headers
xml
<AssignMessage name="SetGzipHeaders">
<Set>
<Headers>
<Header name="Content-Type">application/gzip</Header>
<Header name="Content-Encoding">gzip</Header>
</Headers>
</Set>
</AssignMessage>
```
### 5. **Policy Flow Order**
```
JavaCallout (compress) → AssignMessage (set headers) → TargetEndpoint
Or set headers directly in Java callout as shown above.
Verification Steps
Test with curl on backend directly:
bash
# Create test gzipped file
echo '<test>data</test>' | gzip > test.gz
# Send to your backend
curl -X POST https://your-backend.com/endpoint \
-H "Content-Type: application/gzip" \
-H "Content-Encoding: gzip" \
--data-binary @test.gz -v
If this works, your backend accepts gzip correctly.
Add Debug Policy After Java Callout
xml
<AssignMessage name="DebugCompressed">
<AssignVariable>
<Name>debug.contentLength</Name>
<Value>{request.content.length()}</Value>
</AssignVariable>
<AssignVariable>
<Name>debug.contentType</Name>
<Value>{request.header.Content-Type}</Value>
</AssignVariable>
</AssignMessage>
Check in Trace that debug.contentLength shows a reasonable compressed size.
Validate GZIP Format in Java Callout
Add validation before sending:
java
// After compression, validate it's readable
try (GZIPInputStream testStream = new GZIPInputStream(
new ByteArrayInputStream(compressedData))) {
// If this doesn't throw exception, GZIP is valid
testStream.read();
} catch (Exception e) {
throw new Exception("Generated invalid GZIP: " + e.getMessage());
}
Complete Working Example
java
import com.apigee.flow.execution.*;
import com.apigee.flow.execution.spi.Execution;
import com.apigee.flow.message.MessageContext;
import java.io.*;
import java.util.zip.GZIPOutputStream;
public class GzipCompressor implements Execution {
public ExecutionResult execute(MessageContext msgCtx, ExecutionContext execCtx) {
try {
// Get input
String input = msgCtx.getVariable("inputPayload");
if (input == null || input.isEmpty()) {
msgCtx.setVariable("gzip.error", "inputPayload is empty");
return ExecutionResult.ABORT;
}
// Compress
ByteArrayOutputStream baos = new ByteArrayOutputStream();
try (GZIPOutputStream gzos = new GZIPOutputStream(baos)) {
gzos.write(input.getBytes("UTF-8"));
} // Auto-closes and finalizes GZIP
byte[] compressed = baos.toByteArray();
// Set content and headers
msgCtx.getMessage().setContent(compressed);
msgCtx.setVariable("request.header.Content-Type", "application/gzip");
msgCtx.setVariable("request.header.Content-Encoding", "gzip");
msgCtx.setVariable("request.header.Content-Length",
String.valueOf(compressed.length));
// Debug info
msgCtx.setVariable("gzip.originalSize", input.length());
msgCtx.setVariable("gzip.compressedSize", compressed.length);
return ExecutionResult.SUCCESS;
} catch (Exception e) {
msgCtx.setVariable("gzip.error", e.toString());
return ExecutionResult.ABORT;
}
}
}
Key Takeaways
-
Always close GZIPOutputStream - use try-with-resources
-
Use application/gzip not application/zip
-
Set Content-Encoding: gzip header
-
Call messageContext.getMessage().setContent(bytes)
-
Validate backend expects gzip in body (not Content-Encoding transparent decompression)
The [B@709ec03e in Trace is normal for binary content. Focus on ensuring the Java callout properly closes the GZIP stream and sets correct headers.