Ошибка десериализации в искре с использованием неизменяемого класса с java (+ ломбок) - PullRequest
0 голосов
/ 06 января 2020

У меня есть этот простой класс модели

@Value // lombok - create standard all arg constructor and getters
public class ModelA implements Serializable {
    private String word;
    private double value;
}

И этот простой тест не пройден:

public class SparkSerializationTest {

    private SparkSession spark = SparkSession.builder()
            .master("local")
            .appName("Test")
            .getOrCreate();

    @Test
    public void testSerializationModelA() {
        ModelA   modelA1 = new ModelA("A1", 12.34);
        ModelA   modelA2 = new ModelA("A2", 56.78);

        Dataset<ModelA> dataset = spark.createDataset(
                Arrays.asList(modelA1, modelA2),
                Encoders.bean(ModelA.class));

        List<ModelA> yo = dataset.collectAsList(); // <== *** failure here ***

        assertThat(yo).isEqualTo(Arrays.asList(modelA1, modelA2));
    }
}

с исключением:

java.util.concurrent.ExecutionException: org.codehaus.commons.compiler.CompileException: File 'generated.java', Line 24, Column 67: failed to compile: org.codehaus.commons.compiler.CompileException: File 'generated.java', Line 24, Column 67: No applicable constructor/method found for zero actual parameters; candidates are: "com.xxx.yyy.ModelA(java.lang.String, double)"

Кажется, для этого требуется конструктор с нулевым аргументом Но я хочу, чтобы моя модель была неизменной, то есть с полным конструктором arg и без установщика. Как мне это сделать?

1 Ответ

1 голос
/ 06 января 2020

простой выход

Просто дайте ему конструктор без аргументов без каких-либо установщиков. Это будет изменчиво, но немного менее хаотично c, чем если бы вы предоставили все сеттеры. Когда вы используете Kryo в качестве десериализатора (что, я думаю, вы уже используете), вы можете оставить этот конструктор закрытым.

Конструктор All-Args все еще может вызываться с нулевыми значениями и нечувствительными значениями. Если вы хотите навязать какой-либо договор о действительности объекта, используйте проверку явно. Если вам нужна неизменность, ваши участники больше не будут финальными, используя конструктор без аргументов.

dynamici c природа создания объекта

Десериализация работает, вызывая простейший (без аргументов) конструктор, поскольку это гораздо проще реализовать для авторов используемой утилиты, чем собирать один вызов для всех -args конструктор со всеми необходимыми свойствами, порядок которых может быть произвольным и назначение свойств объекта не гарантируется.

Вместо этого они создают объект vanila и заполняют его через сеттеры или отражения, следя за тем, чтобы имена совпадали между сериализованной и объектной версиями. All-args конструктор сделает это менее надежно и его будет гораздо сложнее реализовать.

Создание пользовательских объектов в Kryo

Если вам нужно сохранить неизменность, вы должны использовать создание пользовательских объектов. Пожалуйста, посмотрите на пример Kryo для создания пользовательских объектов :

Registration registration = kryo.register(SomeClass.class);
registration.setInstantiator(new ObjectInstantiator<SomeClass>() {
  public SomeClass newInstance () {
    return new SomeClass("some constructor arguments", 1234);
  }
});
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...