Skip to content

Adding support for custom data generation using JAR#4024

Open
shreyakhajanchi wants to merge 3 commits into
GoogleCloudPlatform:mainfrom
shreyakhajanchi:custom-dg
Open

Adding support for custom data generation using JAR#4024
shreyakhajanchi wants to merge 3 commits into
GoogleCloudPlatform:mainfrom
shreyakhajanchi:custom-dg

Conversation

@shreyakhajanchi

@shreyakhajanchi shreyakhajanchi commented Jul 14, 2026

Copy link
Copy Markdown
Contributor

Description

This PR introduces the ability to override standard randomized data generation with custom user-defined logic via external JARs.

Key Features

  • Dynamic JAR Loading: Users can now specify a path to an external JAR and a fully qualified class name via pipeline options. The pipeline dynamically loads and caches the custom data generator class at runtime.
  • Custom Data Generator Interface: Introduces a new CustomDataGenerator interface that developers can implement to supply explicit values for specific tables and columns, allowing for complex, stateful, or deterministic data generation scenarios.
  • Improved Error Handling & Logging: Refined exception handling throughout the row assembly process (INSERT, UPDATE, DELETE events). Error messages are now user-facing and clearly surface schema/value mismatches, particularly when integrating with custom generators.
  • Comprehensive Test Coverage: Expanded unit tests across the data generation engine, row assembler, and dynamic fetcher to ensure reliability of the new custom generator code paths.

Impact

This feature unlocks advanced testing and data seeding capabilities, enabling users to inject specific business-logic driven data into their databases without altering the core template code.

@codecov

codecov Bot commented Jul 14, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 76.47059% with 20 lines in your changes missing coverage. Please review.
✅ Project coverage is 55.75%. Comparing base (c8baa96) to head (db5ac6c).
⚠️ Report is 44 commits behind head on main.

Files with missing lines Patch % Lines
.../cloud/teleport/v2/templates/CdcDataGenerator.java 0.00% 5 Missing ⚠️
...eleport/v2/templates/dofn/DataGeneratorEngine.java 54.54% 5 Missing ⚠️
...cloud/teleport/v2/templates/dofn/RowAssembler.java 78.26% 5 Missing ⚠️
...leport/v2/templates/dofn/GeneratePrimaryKeyFn.java 75.00% 3 Missing ⚠️
...v2/templates/utils/CustomDataGeneratorFetcher.java 86.66% 1 Missing and 1 partial ⚠️

❌ Your patch check has failed because the patch coverage (76.47%) is below the target coverage (80.00%). You can increase the patch coverage or adjust the target coverage.

Additional details and impacted files
@@             Coverage Diff              @@
##               main    #4024      +/-   ##
============================================
+ Coverage     55.70%   55.75%   +0.04%     
+ Complexity     7225     6797     -428     
============================================
  Files          1125     1125              
  Lines         68425    68541     +116     
  Branches       7717     7729      +12     
============================================
+ Hits          38119    38215      +96     
- Misses        27835    27845      +10     
- Partials       2471     2481      +10     
Components Coverage Δ
spanner-templates 87.66% <ø> (-0.02%) ⬇️
spanner-import-export 68.87% <ø> (+0.17%) ⬆️
spanner-live-forward-migration 89.29% <ø> (-0.03%) ⬇️
spanner-live-reverse-replication 83.46% <ø> (ø)
spanner-bulk-migration 92.48% <ø> (-0.03%) ⬇️
gcs-spanner-dv 88.55% <ø> (ø)
Files with missing lines Coverage Δ
...teleport/v2/templates/CdcDataGeneratorOptions.java 100.00% <ø> (ø)
...ud/teleport/v2/templates/dofn/BatchAndWriteFn.java 90.09% <100.00%> (+0.37%) ⬆️
...rt/v2/templates/transforms/GeneratePrimaryKey.java 100.00% <100.00%> (ø)
...eleport/v2/templates/utils/DataGeneratorUtils.java 88.43% <100.00%> (+0.66%) ⬆️
...v2/templates/utils/CustomDataGeneratorFetcher.java 86.66% <86.66%> (ø)
...leport/v2/templates/dofn/GeneratePrimaryKeyFn.java 88.46% <75.00%> (-4.57%) ⬇️
.../cloud/teleport/v2/templates/CdcDataGenerator.java 12.76% <0.00%> (-0.57%) ⬇️
...eleport/v2/templates/dofn/DataGeneratorEngine.java 81.97% <54.54%> (-1.29%) ⬇️
...cloud/teleport/v2/templates/dofn/RowAssembler.java 86.82% <78.26%> (-1.68%) ⬇️

... and 43 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@shreyakhajanchi shreyakhajanchi added the addition New feature or request label Jul 20, 2026
@shreyakhajanchi
shreyakhajanchi marked this pull request as ready for review July 20, 2026 08:40
@shreyakhajanchi
shreyakhajanchi requested a review from a team as a code owner July 20, 2026 08:40
@gemini-code-assist

Copy link
Copy Markdown
Contributor

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request enables advanced data seeding by allowing users to override the default randomized data generation with custom, business-logic-driven implementations. By providing a GCS path to a JAR and a class name, users can now inject deterministic or stateful data into their pipelines without modifying the core template code, significantly increasing the flexibility of the CDC data generator.

Highlights

  • Custom Data Generation Support: Introduced a CustomDataGenerator interface allowing users to implement custom logic for data generation, which can be dynamically loaded via external JARs.
  • Dynamic JAR Loading: Added functionality to dynamically load and cache custom generator classes at runtime using pipeline options for JAR path and class name.
  • Improved Error Handling: Enhanced row assembly processes with better exception handling and user-facing error messages, specifically to catch schema or type mismatches when using custom generators.
  • Expanded Test Coverage: Added comprehensive unit tests for the new custom generator logic, including error scenarios and integration tests for the CustomDataGeneratorFetcher.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize the Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counterproductive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces support for custom data generation in the CDC data generator template by adding customJarPath and customClassName parameters. It defines the CustomDataGenerator interface, implements a dynamic class-loading utility (CustomDataGeneratorFetcher), and integrates this custom generator across key data generation components and DoFns. The review feedback highlights two important improvements: first, explicitly specifying a parent classloader when instantiating URLClassLoader to prevent classloading issues in Apache Beam/Dataflow environments; and second, logging the error before throwing a RuntimeException during class loading to ensure visibility in Cloud Logging.

key -> {
try {
URL[] urls = JarFileReader.saveFilesLocally(customJarPath);
URLClassLoader classLoader = URLClassLoader.newInstance(urls);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

In Apache Beam/Dataflow environments, user code and template dependencies are often loaded using a custom worker classloader rather than the system classloader. Creating a URLClassLoader without specifying a parent classloader defaults to using the system classloader as parent. This can lead to NoClassDefFoundError or ClassCastException when the dynamically loaded class tries to reference or cast to the CustomDataGenerator interface.

To prevent this, explicitly pass the classloader of CustomDataGeneratorFetcher as the parent classloader.

Suggested change
URLClassLoader classLoader = URLClassLoader.newInstance(urls);
URLClassLoader classLoader = URLClassLoader.newInstance(urls, CustomDataGeneratorFetcher.class.getClassLoader());

Comment on lines +49 to +56
} catch (Exception e) {
throw new RuntimeException(
"Failed to load CustomDataGenerator from "
+ customJarPath
+ " class: "
+ customClassName,
e);
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

When throwing exceptions in environments where the caller or global exception handler might not log them (such as certain Dataflow templates), log the error message before throwing the exception to ensure the failure is recorded in Cloud Logging.

          } catch (Exception e) {
            LOG.error(
                "Failed to load CustomDataGenerator from {} class: {}",
                customJarPath,
                customClassName,
                e);
            throw new RuntimeException(
                "Failed to load CustomDataGenerator from "
                    + customJarPath
                    + " class: "
                    + customClassName,
                e);
          }
References
  1. When throwing exceptions in environments where the caller or global exception handler might not log them (such as certain Dataflow templates), log the error message before throwing the exception to ensure the failure is recorded.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

addition New feature or request size/XL

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants