Skip to content
Open
Show file tree
Hide file tree
Changes from all 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
9 changes: 6 additions & 3 deletions .github/workflows/build.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,16 @@ jobs:
name: Build
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4

- uses: actions/setup-java@v3
- uses: actions/setup-java@v4
with:
distribution: "corretto"
java-version: "21"
java-version: "17"
cache: "gradle"

- name: Validate styles
uses: pre-commit/action@v3.0.0

- name: Build project
run: ./gradlew clean build
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,12 @@

## Аннотация

Наверняка вы много раз сталкивались с тем, что при работе Hibernate вам приходилось писать много кода по перекладыванию
из `@Entity` в DTO и обратно. Это громоздкий некрасивый boilerplate код, к тому же подверженный ошибкам. И вот, казалось
бы появился спаситель – MapStruct! С помощью codegen он забирает на себя всю рутинную работу по перекладке, а вы лишь
вызываете готовый метод. Но так ли все просто и радужно? В докладе поговорим про сложные случаи, когда нам надо
создавать и обновлять сущности, имеющие связи на другие объекты.

## План

1. Что за настройка `spring.jpa.open-in-view=false` и почему появилась проблема?
Expand Down
16 changes: 16 additions & 0 deletions _config.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
title: JPA example
description: JPA and MapStruct usage example
author:
name: Romanow Alexey
email: romanowalex@mail.ru

show_downloads: false
remote_theme: jekyll/minima
header_pages: ['']

minima:
skin: classic
social_links:
- { platform: linkedin, user_url: "https://www.linkedin.com/company/it-enduro" }
- { platform: telegram, user_url: "https://t.me/romanowalex" }
- { platform: youtube, user_url: "https://www.youtube.com/@it_enduro" }
33 changes: 21 additions & 12 deletions build.gradle
Original file line number Diff line number Diff line change
@@ -1,24 +1,34 @@
plugins {
id "java"
id "idea"
id "org.jetbrains.kotlin.jvm" version "1.9.25"
id "org.jetbrains.kotlin.plugin.jpa" version "1.9.25"
id "org.jetbrains.kotlin.plugin.spring" version "1.9.25"
id "org.jetbrains.kotlin.kapt" version "1.9.25"
id "org.jlleitschuh.gradle.ktlint" version "12.1.2"
id "org.springframework.boot" version "3.5.7"
id "com.gorylenko.gradle-git-properties" version "2.4.2"
id "com.adarshr.test-logger" version "4.0.0"
id "io.spring.dependency-management" version "1.1.7"
}

ext {
springBootVersion = "3.5.8"
mapstructVersion = "1.6.3"
jetbrainsAnnotationsVersion = "22.0.0"
postgresContainerVersion = "1.21.3"
}

idea {
module {
downloadJavadoc = true
downloadSources = true
}
}

ext {
springBootVersion = "3.5.7"
mapstructVersion = "1.6.3"
jetbrainsAnnotationsVersion = "22.0.0"
postgresContainerVersion = "1.21.3"
[compileKotlin, compileTestKotlin]*.kotlinOptions*.jvmTarget = "21"

ktlint {
version.set("1.1.1")
}

repositories {
Expand All @@ -40,13 +50,12 @@ dependencies {
implementation "org.postgresql:postgresql"
implementation "org.flywaydb:flyway-database-postgresql"

implementation "org.jetbrains:annotations:$jetbrainsAnnotationsVersion"
implementation "org.mapstruct:mapstruct:$mapstructVersion"
implementation "org.apache.commons:commons-lang3"

compileOnly "org.projectlombok:lombok"
annotationProcessor "org.projectlombok:lombok"
annotationProcessor "org.mapstruct:mapstruct-processor:$mapstructVersion"
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8"
implementation "org.jetbrains.kotlin:kotlin-reflect"
implementation "com.fasterxml.jackson.module:jackson-module-kotlin"
implementation "org.mapstruct:mapstruct:$mapstructVersion"
kapt "org.mapstruct:mapstruct-processor:$mapstructVersion"

testImplementation "org.springframework.boot:spring-boot-starter-test"
testImplementation "org.springframework.boot:spring-boot-testcontainers"
Expand Down
14 changes: 7 additions & 7 deletions src/main/java/ru/romanow/jpa/JpaExampleApplication.kt
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
package ru.romanow.jpa;
package ru.romanow.jpa

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

@SpringBootApplication
public class JpaExampleApplication {
public static void main(String[] args) {
SpringApplication.run(JpaExampleApplication.class, args);
}
class JpaExampleApplication

fun main(args: Array<String>) {
runApplication<JpaExampleApplication>(*args)
}
66 changes: 29 additions & 37 deletions src/main/java/ru/romanow/jpa/domain/Address.kt
Original file line number Diff line number Diff line change
@@ -1,57 +1,49 @@
package ru.romanow.jpa.domain;
package ru.romanow.jpa.domain

import lombok.Data;
import lombok.experimental.Accessors;
import org.apache.commons.lang3.builder.ToStringBuilder;
import jakarta.persistence.*

import jakarta.persistence.*;
import java.util.List;
import java.util.Objects;
import java.util.StringJoiner;

@Data
@Accessors(chain = true)
@Entity
@Table(name = "address")
public class Address {

data class Address(
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
val id: Int? = null,

@Column(name = "city", nullable = false)
private String city;
var city: String? = null,

@Column(name = "country", nullable = false)
private String country;
var country: String? = null,

@Column(name = "street")
private String street;
var street: String? = null,

@Column(name = "address", nullable = false)
private String address;

@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Address other = (Address) o;
return Objects.equals(city, other.city) && Objects.equals(country, other.country) && Objects.equals(street, other.street) && Objects.equals(address, other.address);
var address: String? = null,
) {
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other !is Address) return false

if (id != other.id) return false
if (city != other.city) return false
if (country != other.country) return false
if (street != other.street) return false
if (address != other.address) return false

return true
}

@Override
public int hashCode() {
return Objects.hash(city, country, street, address);
override fun hashCode(): Int {
var result = id ?: 0
result = 31 * result + (city?.hashCode() ?: 0)
result = 31 * result + (country?.hashCode() ?: 0)
result = 31 * result + (street?.hashCode() ?: 0)
result = 31 * result + (address?.hashCode() ?: 0)
return result
}

@Override
public String toString() {
return new ToStringBuilder(this)
.append("id", id)
.append("city", city)
.append("country", country)
.append("street", street)
.append("address", address)
.toString();
override fun toString(): String {
return "Address(id=$id, city=$city, country=$country, street=$street, address=$address)"
}
}
56 changes: 24 additions & 32 deletions src/main/java/ru/romanow/jpa/domain/Authority.kt
Original file line number Diff line number Diff line change
@@ -1,50 +1,42 @@
package ru.romanow.jpa.domain;
package ru.romanow.jpa.domain

import lombok.Data;
import lombok.experimental.Accessors;
import org.apache.commons.lang3.builder.ToStringBuilder;
import jakarta.persistence.*

import jakarta.persistence.*;
import java.util.Objects;

@Data
@Accessors(chain = true)
@Entity
@Table(name = "authority")
public class Authority {

data class Authority(
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
val id: Int? = null,

@Column(name = "name", length = 80, nullable = false)
private String name;
var name: String? = null,

@Column(name = "priority", nullable = false)
private Integer priority;
var priority: Int? = null,

@ManyToOne(fetch = FetchType.LAZY)
private Person person;

@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Authority grant = (Authority) o;
return Objects.equals(id, grant.id) && Objects.equals(name, grant.name) && Objects.equals(priority, grant.priority);
val person: Person? = null,
) {
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other !is Authority) return false

if (id != other.id) return false
if (name != other.name) return false
if (priority != other.priority) return false

return true
}

@Override
public int hashCode() {
return Objects.hash(id, name, priority);
override fun hashCode(): Int {
var result = id ?: 0
result = 31 * result + (name?.hashCode() ?: 0)
result = 31 * result + (priority ?: 0)
return result
}

@Override
public String toString() {
return new ToStringBuilder(this)
.append("id", id)
.append("name", name)
.append("priority", priority)
.toString();
override fun toString(): String {
return "Authority(id=$id, name=$name, priority=$priority)"
}
}
Loading