Migration Deep Dive für 06 · Batch öffnen →
⌂ ÜbersichtAlle Vergleiche
Modul 06 · 100 % Codeabdeckung

Batch

Vollständiger Legacy-Modern-Vergleich aller Java-Klassen, Tests, Maven-POMs und relevanten Ressourcen dieses Moduls. Jede Datei ist genau einmal einer fachlich passenden Vergleichsgruppe zugeordnet.

7Legacy-Dateien
7Modern-Dateien
98 → 167Codezeilen
15/15vollständig erfasst

Fachliche Einordnung

Legacy

Manueller Dateiimport

Ein eigener Importer liest Zeilen, überspringt den Header und mappt sie in einem Durchlauf.

Modern

Spring-Batch Job mit Reader/Processor/Writer

Reader, Processor, Writer, Step und Job sind getrennte, wiederanlaufbare Batch-Bausteine.

Vergleichsfokus: Alle Dateien werden nach technischer Rolle und fachlicher Verantwortung gruppiert.
Wichtige Abgrenzung: One-to-many-Änderungen werden als Gruppe dargestellt; eine künstliche 1:1-Zuordnung wird vermieden.

Vollständige Abdeckungsmatrix

Die Ähnlichkeit ist eine technische Orientierung auf normalisiertem Quelltext. Sie ersetzt keine fachliche Bewertung.

VergleichsgruppeLegacy-DateienModern-DateienLegacy-ZeilenModern-ZeilenÄhnlichkeit
Build-Konfiguration11315242%
Bootstrap und Konfiguration12131420%
Datenmodell und Beispieldaten22101090%
Parser/Importer und Batch-Job-Test32449115%

Gemeinsame Modulstruktur

Das Pair-POM bindet die Legacy- und Modern-Submodule zusammen und gehört deshalb ebenfalls zur vollständigen Codeabdeckung.

Gemeinsam · 19 Zeilenpom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>at.aydin.academy</groupId>
        <artifactId>java-modernization-deep-dive</artifactId>
        <version>1.0.0</version>
        <relativePath>../../pom.xml</relativePath>
    </parent>
    <artifactId>06batch-pair</artifactId>
    <packaging>pom</packaging>
    <name>Batch: Legacy und Modern</name>
    <modules>
        <module>legacy</module>
        <module>modern</module>
    </modules>
</project>

Alle semantischen Codevergleiche

01Build-KonfigurationDirektvergleich · Legacy 31 / Modern 52 Zeilen · Ähnlichkeit 42%

Manuelle Batch-Abhängigkeiten und Spring Batch werden verglichen.

Legacy-DateienModern-DateienEinordnung
pom.xmlpom.xmlDirektvergleich
Semantische Ähnlichkeit: 42%

Legacy

Legacy · 31 Zeilenlegacy/pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>at.aydin.academy</groupId>
        <artifactId>06batch-pair</artifactId>
        <version>1.0.0</version>
        <relativePath>../pom.xml</relativePath>
    </parent>
    <artifactId>batch-legacy</artifactId>
    <packaging>jar</packaging>
    <name>Batch Legacy</name>
    <dependencies>
        <dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
            </plugin>

        </plugins>
    </build>
</project>

Modern

Modern · 52 Zeilenmodern/pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>at.aydin.academy</groupId>
        <artifactId>06batch-pair</artifactId>
        <version>1.0.0</version>
        <relativePath>../pom.xml</relativePath>
    </parent>
    <artifactId>batch-modern</artifactId>
    <packaging>jar</packaging>
    <name>Batch Modern (Spring Batch)</name>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-batch</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jdbc</artifactId>
        </dependency>
        <dependency>
            <groupId>com.h2database</groupId>
            <artifactId>h2</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.batch</groupId>
            <artifactId>spring-batch-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
            </plugin>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>
02Bootstrap und KonfigurationDirektvergleich · Legacy 13 / Modern 14 Zeilen · Ähnlichkeit 20%

Standalone-Aufruf wird auf Spring-Boot-Batchbetrieb umgestellt.

Legacy-DateienModern-DateienEinordnung
BatchLegacyApplication.javaBatchModernApplication.java
application.properties
Direktvergleich
Semantische Ähnlichkeit: 20%

Legacy

package at.aydin.lab.batch.legacy;

import java.nio.file.Path;

public final class BatchLegacyApplication {
    private BatchLegacyApplication() {
    }

    public static void main(String[] args) throws Exception {
        Path input = args.length == 0 ? Path.of("src/main/resources/sample-orders.csv") : Path.of(args[0]);
        new LegacyBatchImporter().importFile(input).forEach(System.out::println);
    }
}

Modern

package at.aydin.lab.batch.modern;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class BatchModernApplication {
    public static void main(String[] args) {
        SpringApplication.run(BatchModernApplication.class, args);
    }
}
03Datenmodell und BeispieldatenDirektvergleich · Legacy 10 / Modern 10 Zeilen · Ähnlichkeit 90%

Datensatz und Eingabedatei bleiben fachlich direkt vergleichbar.

Legacy-DateienModern-DateienEinordnung
OrderRow.java
sample-orders.csv
OrderRow.java
sample-orders.csv
Direktvergleich
Semantische Ähnlichkeit: 90%

Legacy

Modern

04Parser/Importer und Batch-Job-TestDirektvergleich · Legacy 44 / Modern 91 Zeilen · Ähnlichkeit 15%

Selbstgebauter Import wird durch deklarative Job-/Step-Konfiguration ersetzt.

Legacy-DateienModern-DateienEinordnung
CsvOrderParser.java
LegacyBatchImporter.java
CsvOrderParserTest.java
BatchConfiguration.java
BatchConfigurationTest.java
Direktvergleich
Semantische Ähnlichkeit: 15%

Legacy

package at.aydin.lab.batch.legacy;

import java.math.BigDecimal;

// Design Pattern: Mapper
// Zweck: Transportformat CSV wird in ein fachliches Objekt übersetzt.
public final class CsvOrderParser {
    public OrderRow parse(String line) {
        String[] columns = line.split(",", -1);
        if (columns.length != 3) throw new IllegalArgumentException("Ungültige CSV-Zeile: " + line);
        return new OrderRow(Long.parseLong(columns[0].trim()), columns[1].trim(), new BigDecimal(columns[2].trim()));
    }
}
package at.aydin.lab.batch.legacy;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.List;

// Design Pattern: Template Method (manuell angedeutet)
// Zweck: Lesen, Überspringen, Parsen und Schreiben bilden einen festen Batch-Ablauf.
public final class LegacyBatchImporter {
    private final CsvOrderParser parser = new CsvOrderParser();
    public List<OrderRow> importFile(Path path) throws IOException {
        try (var lines = Files.lines(path)) {
            return lines.skip(1).filter(line -> !line.isBlank()).map(parser::parse).toList();
        }
    }
}
package at.aydin.lab.batch.legacy;

import org.junit.jupiter.api.Test;
import java.math.BigDecimal;
import static org.junit.jupiter.api.Assertions.assertEquals;

class CsvOrderParserTest {
    @Test
    void parsesRow() {
        OrderRow row = new CsvOrderParser().parse("7,Test AG,12.30");
        assertEquals(7, row.id());
        assertEquals(new BigDecimal("12.30"), row.amount());
    }
}

Modern

package at.aydin.lab.batch.modern;

import javax.sql.DataSource;
import org.springframework.batch.core.Job;
import org.springframework.batch.core.Step;
import org.springframework.batch.core.job.builder.JobBuilder;
import org.springframework.batch.core.repository.JobRepository;
import org.springframework.batch.core.step.builder.StepBuilder;
import org.springframework.batch.item.ItemProcessor;
import org.springframework.batch.item.database.JdbcBatchItemWriter;
import org.springframework.batch.item.database.builder.JdbcBatchItemWriterBuilder;
import org.springframework.batch.item.file.FlatFileItemReader;
import org.springframework.batch.item.file.builder.FlatFileItemReaderBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
import org.springframework.jdbc.core.namedparam.MapSqlParameterSource;
import org.springframework.transaction.PlatformTransactionManager;

@Configuration
// Design Pattern: Pipeline
// Zweck: Reader, Processor und Writer sind austauschbare, getrennt testbare Batch-Stufen.
public class BatchConfiguration {
    @Bean
    FlatFileItemReader<OrderRow> orderReader() {
        return new FlatFileItemReaderBuilder<OrderRow>()
                .name("orderReader")
                .resource(new ClassPathResource("sample-orders.csv"))
                .linesToSkip(1)
                .delimited()
                .names("id", "customer", "amount")
                .fieldSetMapper(fieldSet -> new OrderRow(
                        fieldSet.readLong("id"),
                        fieldSet.readString("customer"),
                        fieldSet.readBigDecimal("amount")))
                .build();
    }

    @Bean
    ItemProcessor<OrderRow, OrderRow> positiveAmountProcessor() {
        return item -> item.amount().signum() > 0 ? item : null;
    }

    @Bean
    JdbcBatchItemWriter<OrderRow> orderWriter(DataSource dataSource) {
        return new JdbcBatchItemWriterBuilder<OrderRow>()
                .dataSource(dataSource)
                .sql("insert into imported_order(id,customer,amount) "
                        + "values (:id,:customer,:amount)")
                .itemSqlParameterSourceProvider(item -> new MapSqlParameterSource()
                        .addValue("id", item.id())
                        .addValue("customer", item.customer())
                        .addValue("amount", item.amount()))
                .build();
    }

    @Bean
    Step importOrders(
            JobRepository jobRepository,
            PlatformTransactionManager transactionManager,
            FlatFileItemReader<OrderRow> orderReader,
            ItemProcessor<OrderRow, OrderRow> positiveAmountProcessor,
            JdbcBatchItemWriter<OrderRow> orderWriter) {
        return new StepBuilder("importOrders", jobRepository)
                .<OrderRow, OrderRow>chunk(10, transactionManager)
                .reader(orderReader)
                .processor(positiveAmountProcessor)
                .writer(orderWriter)
                .build();
    }

    @Bean
    Job importOrderJob(JobRepository jobRepository, Step importOrders) {
        return new JobBuilder("importOrderJob", jobRepository)
                .start(importOrders)
                .build();
    }
}
package at.aydin.lab.batch.modern;

import org.junit.jupiter.api.Test;
import java.math.BigDecimal;
import static org.junit.jupiter.api.Assertions.assertEquals;

class BatchConfigurationTest {
    @Test
    void recordKeepsValues() {
        OrderRow row = new OrderRow(1, "Test", new BigDecimal("10.00"));
        assertEquals("Test", row.customer());
    }
}
⌂ Cockpit