Skip to content
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

Fix the non-default constructor mechanism of bytecode recording #31183

Merged
merged 4 commits into from
Feb 16, 2023
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -1173,6 +1173,13 @@ public void prepare(MethodContext context) {
nonDefaultConstructorHandles[i] = loadObjectInstance(obj, existing,
parameterTypes[count++], relaxedValidation);
}
if (nonDefaultConstructorHolder.constructor.getParameterCount() > 0) {
Parameter[] parameters = nonDefaultConstructorHolder.constructor.getParameters();
for (int i = 0; i < parameters.length; ++i) {
String name = parameters[i].getName();
gastaldi marked this conversation as resolved.
Show resolved Hide resolved
constructorParamNameMap.put(name, i);
}
}
} else if (classesToUseRecordableConstructor.contains(param.getClass())) {
Constructor<?> current = null;
int count = 0;
Expand All @@ -1191,7 +1198,7 @@ public void prepare(MethodContext context) {
nonDefaultConstructorHandles = new DeferredParameter[current.getParameterCount()];
if (current.getParameterCount() > 0) {
Parameter[] parameters = current.getParameters();
for (int i = 0; i < current.getParameterCount(); ++i) {
for (int i = 0; i < parameters.length; ++i) {
String name = parameters[i].getName();
constructorParamNameMap.put(name, i);
}
Expand All @@ -1215,7 +1222,7 @@ public void prepare(MethodContext context) {

if (selectedCtor.getParameterCount() > 0) {
Parameter[] ctorParameters = selectedCtor.getParameters();
for (int i = 0; i < selectedCtor.getParameterCount(); ++i) {
for (int i = 0; i < ctorParameters.length; ++i) {
String name = ctorParameters[i].getName();
constructorParamNameMap.put(name, i);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package io.quarkus.deployment.recording;

import static org.assertj.core.api.Assertions.assertThatCode;
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
Expand Down Expand Up @@ -137,6 +138,30 @@ public void testJavaBean() throws Exception {
}, new TestJavaBeanSubclass("A string", 99, "PUT"));
}

@Test
public void testJobDetails() throws Exception {
runTest(generator -> {
assertThatCode(() -> {
generator.registerNonDefaultConstructor(
JobParameter.class.getDeclaredConstructor(String.class, String.class, Object.class),
jobParameter -> Arrays.asList(
jobParameter.getClassName(),
jobParameter.getActualClassName(),
jobParameter.getObject()));
generator.registerNonDefaultConstructor(
JobDetails.class.getDeclaredConstructor(String.class, String.class, String.class, List.class),
jobDetails -> Arrays.asList(
jobDetails.getClassName(),
jobDetails.getStaticFieldName(),
jobDetails.getMethodName(),
jobDetails.getJobParameters()));
}).doesNotThrowAnyException();
TestRecorder recorder = generator.getRecordingProxy(TestRecorder.class);
recorder.bean(new JobDetails("A string", null, "methodName", List.of(JobParameter.JobContext)));
}, new JobDetails("A string", null, "methodName", List.of(JobParameter.JobContext)));

}

@Test
public void testValidationFails() throws Exception {
Assertions.assertThrows(RuntimeException.class, () -> {
Expand Down Expand Up @@ -190,11 +215,7 @@ public String get() {
@Test
public void testLargeCollection() throws Exception {

List<TestJavaBean> beans = new ArrayList<>();
for (int i = 0; i < 100000; ++i) {
beans.add(new TestJavaBean("A string", 99));
}

List<TestJavaBean> beans = Collections.nCopies(100000, new TestJavaBean("A string", 99));
runTest(generator -> {
TestRecorder recorder = generator.getRecordingProxy(TestRecorder.class);
recorder.list(beans);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
package io.quarkus.deployment.recording;

import static java.util.Collections.unmodifiableList;

import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

public class JobDetails {

private final String className;
private final String staticFieldName;
private final String methodName;
private final ArrayList<JobParameter> jobParameters;
private Boolean cacheable;

private JobDetails() {
this(null, null, null, null);
// used for deserialization
}

public JobDetails(String className, String staticFieldName, String methodName, List<JobParameter> jobParameters) {
this.className = className;
this.staticFieldName = staticFieldName;
this.methodName = methodName;
this.jobParameters = new ArrayList<>(jobParameters);
this.cacheable = false;
}

public String getClassName() {
return className;
}

public String getStaticFieldName() {
return staticFieldName;
}

public boolean hasStaticFieldName() {
return staticFieldName != null;
}

public String getMethodName() {
return methodName;
}

public List<JobParameter> getJobParameters() {
return unmodifiableList(jobParameters);
}

public Class[] getJobParameterTypes() {
return jobParameters.stream()
.map(JobParameter::getClassName)
.toArray(Class[]::new);
}

public Object[] getJobParameterValues() {
return jobParameters.stream()
.map(JobParameter::getObject)
.toArray();
}

public Boolean getCacheable() {
return cacheable;
}

public void setCacheable(boolean cacheable) {
this.cacheable = cacheable;
}

@Override
public boolean equals(Object o) {
if (this == o)
return true;
if (!(o instanceof JobDetails))
return false;
JobDetails that = (JobDetails) o;
return Objects.equals(className, that.className)
&& Objects.equals(staticFieldName, that.staticFieldName)
&& Objects.equals(methodName, that.methodName)
&& Objects.equals(jobParameters, that.jobParameters)
&& Objects.equals(cacheable, that.cacheable);
}

@Override
public int hashCode() {
return Objects.hash(className, staticFieldName, methodName, jobParameters, cacheable);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
package io.quarkus.deployment.recording;

import java.util.Objects;

public class JobParameter {
public static final JobParameter JobContext = new JobParameter(JobParameter.class);

private String className;
private String actualClassName;
private Object object;

private JobParameter() {
// used for deserialization
}

private JobParameter(Class<?> clazz) {
this(clazz.getName(), null);
}

public JobParameter(Class<?> clazz, Object object) {
this(clazz.getName(), object);
}

public JobParameter(Object object) {
this(object.getClass().getName(), object);
}

public JobParameter(String className, Object object) {
this(className, isNotNullNorAnEnum(object) ? object.getClass().getName() : className, object);
}

public JobParameter(String className, String actualClassName, Object object) {
this.className = className;
this.actualClassName = actualClassName;
this.object = object;
}

/**
* Represents the class name expected by the job method (e.g. an object or an interface)
*
* @return the class name expected by the job method (e.g. an object or an interface)
*/
public String getClassName() {
return className;
}

/**
* Represents the actual class name of the job parameter (e.g. an object), this will never be an interface
*
* @return the actual class name of the job parameter (e.g. an object), this will never be an interface
*/
public String getActualClassName() {
return actualClassName;
}

/**
* The actual job parameter
*
* @return the actual job parameter
*/
public Object getObject() {
return object;
}

@Override
public boolean equals(Object o) {
if (this == o)
return true;
if (!(o instanceof JobParameter))
return false;
JobParameter that = (JobParameter) o;
return Objects.equals(className, that.className)
&& Objects.equals(actualClassName, that.actualClassName)
&& Objects.equals(object, that.object);
}

@Override
public int hashCode() {
return Objects.hash(className, actualClassName, object);
}

protected static boolean isNotNullNorAnEnum(Object object) {
return object != null && !(object instanceof Enum);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,10 @@ public void bean(TestJavaBean bean) {
RESULT.add(bean);
}

public void bean(JobDetails jobDetails) {
RESULT.add(jobDetails);
}

public void bean(TestJavaBeanWithBoolean bean) {
RESULT.add(bean);
}
Expand Down