Skip to content

Commit

Permalink
feat: record support in beanpropertyset (#19259)
Browse files Browse the repository at this point in the history
  • Loading branch information
tepi authored Apr 26, 2024
1 parent 6317a21 commit ff10370
Show file tree
Hide file tree
Showing 2 changed files with 51 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
*/
package com.vaadin.flow.data.binder;

import java.beans.PropertyDescriptor;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
Expand All @@ -34,6 +35,7 @@
import org.junit.Test;

import com.vaadin.flow.function.ValueProvider;
import com.vaadin.flow.internal.BeanUtil;
import com.vaadin.flow.tests.data.bean.Address;
import com.vaadin.flow.tests.data.bean.Country;
import com.vaadin.flow.tests.data.bean.FatherAndSon;
Expand Down Expand Up @@ -72,6 +74,9 @@ public String toString() {
}
}

public record TestRecord(String name, int age) {
}

interface Iface3 extends Iface2, Iface {
}

Expand Down Expand Up @@ -217,6 +222,39 @@ public void testSerializeDeserialize_nestedPropertyDefinition()
address.getPostalCode(), postalCode);
}

@Test
public void testSerializeDeserializeRecord() throws Exception {
PropertyDefinition<TestRecord, ?> definition = BeanPropertySet
.get(TestRecord.class).getProperty("name")
.orElseThrow(AssertionFailedError::new);

PropertyDefinition<TestRecord, ?> deserializedDefinition = ClassesSerializableUtils
.serializeAndDeserialize(definition);

ValueProvider<TestRecord, ?> getter = deserializedDefinition
.getGetter();

TestRecord testRecord = new TestRecord("someone", 42);

String name = (String) getter.apply(testRecord);

Assert.assertEquals("Deserialized definition should be functional",
"someone", name);

PropertyDescriptor namePropertyDescriptor = BeanUtil
.getPropertyDescriptor(TestRecord.class, "name");
Assert.assertNotNull(namePropertyDescriptor);
Assert.assertEquals("Property has unexpected name",
namePropertyDescriptor.getName(), "name");
Assert.assertEquals("Property read method has unexpected name",
namePropertyDescriptor.getReadMethod().getName(), "name");

Class<?> namePropertyType = BeanUtil.getPropertyType(TestRecord.class,
"name");
Assert.assertEquals("Property type is unexpected", namePropertyType,
String.class);
}

@Test
public void nestedPropertyDefinition_samePropertyNameOnMultipleLevels() {
PropertyDefinition<FatherAndSon, ?> definition = BeanPropertySet
Expand Down
14 changes: 13 additions & 1 deletion flow-server/src/main/java/com/vaadin/flow/internal/BeanUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import java.io.Serializable;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.RecordComponent;
import java.util.ArrayList;
import java.util.List;

Expand All @@ -42,7 +43,7 @@ private BeanUtil() {
}

/**
* Returns the property descriptors of a class or an interface.
* Returns the property descriptors of a class, a record, or an interface.
*
* For an interface, superinterfaces are also iterated as Introspector does
* not take them into account (Oracle Java bug 4275879), but in that case,
Expand All @@ -66,6 +67,17 @@ private BeanUtil() {
*/
public static List<PropertyDescriptor> getBeanPropertyDescriptors(
final Class<?> beanType) throws IntrospectionException {

if (beanType.isRecord()) {
List<PropertyDescriptor> propertyDescriptors = new ArrayList<>();

for (RecordComponent component : beanType.getRecordComponents()) {
propertyDescriptors.add(new PropertyDescriptor(
component.getName(), component.getAccessor(), null));
}

return propertyDescriptors;
}
// Oracle bug 4275879: Introspector does not consider superinterfaces of
// an interface
if (beanType.isInterface()) {
Expand Down

0 comments on commit ff10370

Please sign in to comment.