-
Notifications
You must be signed in to change notification settings - Fork 38.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add support for common value objects and records to ValueCodeGenerator #32263
Add support for common value objects and records to ValueCodeGenerator #32263
Conversation
Add support for generating code to create common value Objects and Records. A common value Record is a public, accessible Record class that has common value objects for all of its components. A common value Object is a public, accessible Object class that has public setters for all of its non-public instance fields, with each field being assigned a common value. The code generated for a common value Record calls the Record's canonical constructor with the generated code for each of its component. For instance, for `record MyRecord(String a, int b)`, and instance `MyRecord("Example", 1)`, it would generate the following code: new MyRecord("Example", 1) The code generated for a common value Object calls the Object's public no-args constructor and sets its fields. Public fields are set by direct access. Non-public fields are set by calling their setters. The code will be wrapped by an inlined Supplier so the generated code can be used anywhere. For example, given the following class: class MyObject { public String name; private int age; public void setAge(int age) { this.age = age; } } The code generated for MyObject("Example", 2) would be ((Supplier<MyObject>) () -> { MyObject $valueCodeGeneratorObject1 = new MyObject(); $valueCodeGeneratorObject1.setAge(2); $valueCodeGeneratorObject1.name = "Example"; return $valueCodeGeneratorObject1; }).get() ValueCodeGenerator uses a ThreadLocal keeping track of the number of generateCode calls in the current Thread's stack. This allows the Delegate for Object to use an unused identifier for the variable holding the Object under construction. Known limitations are that cyclic references cannot be handled. If a cyclic reference is detected, a ValueCodeGenerationException will be raised. Additionally, if the same Object is used for multiple fields/components in Objects/Records, they will be different instances instead of the same instance. This change will allow common value objects and records to be passed to the constructor of BeanDefinitions in an AOT native image. For instance, the following will now work in native image, provided `myConfig` is a common value object: MyConfig myConfig = new MyConfig(); // ...Set fields of MyConfig ... RootBeanDefinition rootBeanDefinition = new RootBeanDefinition( MyBean.class); rootBeanDefinition.setFactoryMethodName("of"); rootBeanDefinition.getConstructorArgumentValues() .addGenericArgumentValue(myConfig); registry.registerBeanDefinition(BEAN_NAME, rootBeanDefinition);
ValueCodeGenerator
Thanks for the PR.
Do I understand that what this does is taking an existing class structure and attempt to restore its state in a generic fashion? If so, we have no intention to bring that complexity to the core framework. Assuming that the record has been initialized via some code of yours, is there something specific that prevents you from getting the expected result? |
ValueCodeGenerator
ValueCodeGenerator
ValueCodeGenerator
Actually, I can answer my own question. @Christopher-Chianelli before spending time to submit such a large PR, please consider raising an issue first to discuss the merit of the change, especially as we already had a conversation where I thought I made it clear that we didn't want to do that. If you're still having an issue with the record re-created with your own code, please raise an issue with more details. |
JAX-B seems to be unsupported in native image (GraalVM issue) without either including a 9000+ lines
Per the second point of https://github.com/spring-projects/spring-framework/blob/main/CONTRIBUTING.md#submit-a-pull-request , I figured I might as create a PR since the majority of the work was already done when submitting the equivalent of this PR upstream to JavaPoet (square/javapoet#999), and I figured other users of Spring stands to benefit from it, since it allows use cases such as @Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
MyRecord myRecord = generateRecord();
RootBeanDefinition rootBeanDefinition = new RootBeanDefinition(MyBean.class);
rootBeanDefinition.setFactoryMethodName("from");
rootBeanDefinition.getConstructorArgumentValues().addGenericArgumentValue(
myRecord);
registry.registerBeanDefinition("MyBean", rootBeanDefinition);
} to also work in native image (currently fails with |
Add support for generating code to create common value Objects and Records. A common value Record is a public, accessible Record class that has common value objects for all of its components. A common value Object is a public, accessible Object class that has public setters for all of its non-public instance fields, with each field being assigned a common value.
The code generated for a common value Record calls the Record's canonical constructor with the generated code for each of its component. For instance, for
record MyRecord(String a, int b)
, and instanceMyRecord("Example", 1)
, it would generate the following code:The code generated for a common value Object calls the Object's public no-args constructor and sets its fields. Public fields are set by direct access. Non-public fields are set by calling their setters. The code will be wrapped by an inlined Supplier so the generated code can be used anywhere. For example, given the following class:
The code generated for MyObject("Example", 2) would be
ValueCodeGenerator uses a ThreadLocal keeping track of the number of generateCode calls in the current Thread's stack. This allows the Delegate for Object to use an unused identifier for the variable holding the Object under construction.
Known limitations are that cyclic references cannot be handled. If a cyclic reference is detected, a ValueCodeGenerationException will be raised.
Additionally, if the same Object is used for multiple fields/components in Objects/Records, they will be different instances instead of the same instance.
This change will allow common value objects and records to be passed to the constructor of BeanDefinitions in an AOT native image. For instance, the following will now work in native image, provided
myConfig
is a common value object: