메서드 레퍼런스는 람다 표현식으로 구현할 때 단 하나의 메서드만을 호출하는 경우 축약해서 매개변수 없이 사용할 수 있도록 해준다. // 람다 표현식 (s) -> System.out.println(s); // 메서드 레퍼런스 System.out::println; 기존에는 직접 구현을 통해 람다를 사용했었다. 하지만 이미 그 기능을 하는 메서드가 존재한다면 메서드 레퍼런스로 더 간단히 표현할 수 있다. 메서드 참조하는 방법 static 메서드 참조 타입::스태틱 메서드 형태로 표현한다. public class Greeting { private String name; public static hello(String name) { return "hello" + name; } } public class Run {..
김영한님의 자바 ORM 표준 JPA 프로그래밍 강의를 들으며 공부한 내용을 정리한 글입니다. 객체와 테이블 매핑 JPA를 사용해 어떤 테이블과 매핑할 클래스는 @Entity 애너테이션을 필수적으로 명시해줘야 한다. 즉, @Entity가 붙은 클래스는 JPA가 관리하는 클래스라는 것을 나타낸다. @Entity public class Member { ..... ..... } Entity 클래스를 만들 때 몇 가지 주의할 점이 있는데, 주의 사항은 다음과 같다. 주의사항 public 혹은 protected 레벨의 파라미터가 없는 기본 생성자는 필수이다. final 클래스, enum, interface, inner 클래스는 Entity로 사용할 수 없다. 값을 담는 필드에 final을 사용하면 안 된다. @En..
김영한님의 자바 ORM 표준 JPA 프로그래밍 강의를 들으며 공부한 내용을 정리한 글입니다. JPA의 내부 동작 방식을 이해하기 위한 중요한 개념이 있다. 바로 영속성 컨텍스트이다. 영속성 컨텍스트 영속성 컨텍스트는 JPA를 이해하는데 가장 중요한 용어로써 "엔티티를 영구 저장하는 환경"이라는 뜻이다. 우리는 아래와 같이 EntityManager를 통해 값을 영속화시킬 수 있다. EntityManager.persist(entity); 하지만 실제 EntityManager는 값을 DB에 저장하는 것이 아니라 영속성 컨텍스트에 저장한다. 눈에 보이지 않는 논리적 개념으로 하나의 EntityManager는 하나의 영속성 컨텍스트를 가지고 있다.(Spring Data는 N:1) 영속성 컨텍스트의 라이프 사이클 ..
Serializable을 구현하기로 결정한 순간부터 생성자 이외의 방법으로 인스턴스를 생성할 수 있게 된다. 이 말은 버그와 보안 문제가 일어날 가능성이 커진다는 뜻이다. 하지만 이러한 위험을 크게 줄여주는 기법이 있다. 바로 직렬화 프록시 패턴이다. 직렬화 프록시 패턴 직렬화 프록시 패턴은 가짜 바이트 스트림 공격과 내부 필드 탈취 공격을 프록시 수준에서 차단해준다. 직렬화 프록시 패턴의 구조 바깥 클래스의 논리적 상태를 정밀하게 표현하는 중첩 클래스를 설계해 private static으로 선언한다. 이 중첩 클래스가 바깥 클래스의 직렬화 프록시이다. 중첩 클래스의 생성자는 단 하나여야 하며, 바깥 클래스를 매개변수로 받는다. 생성자는 단순히 인수로 넘어온 인스턴스를 복사한다. (일관성 검사 및 방어적..
싱글턴 패턴과 직렬화 진짜 싱글턴일까? item3에서 소개된 싱글턴 패턴 예제를 살펴보면, 생성자를 호출하지 못하게 막는 방식으로 인스턴스가 하나만 만들어짐을 보장했다. // 인스턴스가 하나만 만들어짐을 보장하는 클래스 public class Elvis { public static final Elvis INSTANCE = new Elvis(); private Elvis() { } public void leaveTheBuilding() { ... } } 하지만 이 클래스는 Serializable을 추가하는 순간 더 이상 싱글턴이 아니게 된다. 기본 직렬화를 사용하지 않아도, readObject 메서드를 제공하지 않아도 소용없다. 어떤 readObject 메서드를 사용하더라도 이 클래스가 초기화될 때 만들어..
방어적 복사(가변 필드)를 사용하는 불변 클래스의 Serializable 구현 item50에서는 불변 날짜 범위 클래스를 만드는데 가변 Date 필드를 이용했다. 따라서 불변식을 지키기 위해 생성자와 접근자에 Date 객체를 방어적으로 복사하느라 코드가 상당히 길어졌다. public final class Period { private final Date start; private final Date end; // 수정한 생성자 - 매개변수의 방어적 복사본을 만든다. public Period(Date start, Date end) { this.start = new Date(start.getTime()); this.end = new Date(end.getTime()); if (start.compareTo(e..
클래스가 Serializable을 구현하고 기본 직렬화 형태를 사용한다면, 향후 릴리스에서도 현재의 구현에 영원히 발이 묶이게 된다. 즉, 기본 직렬화 형태를 버리고 싶어도 버릴 수 없게 된다. 실제로 BigInteger 같은 자바 클래스도 같은 문제를 겪고 있다. 기본 직렬화 형태는 유연성, 성능, 정확성 측면에서 신중히 고민한 후 합당할 때만 사용해야 한다. 기본 직렬화 형태 사용이 합당한 경우 직접 설계해도 기본 직렬화 형태와 거의 같은 결과가 나올 경우에만 기본 형태를 사용해야 한다. 기본 직렬화 형태는 어떤 객체가 포함한 데이터들과 그 객체에서부터 시작해 접근할 수 있는 모든 객체를 담아내며, 그 객체들이 연결된 위상까지 기술한다. 이상적인 직렬화 형태라면 물리적인 모습과 논리적인 모습만을 표현..
클래스 선언에 implements Serializable만 붙이면 어떤 클래스의 인스턴스던 직렬화 할 수 있다. 너무 쉽게 적용할 수 있기 때문에 특별히 신경 쓸게 없다고 생각할 수 있지만, 실제로는 훨씬 복잡하고 신경 써야 할 부분이 많다. Serializable 구현 시 주의 사항 릴리스 후 수정이 어려워진다. Serializable을 구현하면 릴리스 한 뒤에는 수정하기 어려워진다. Serializable을 구현한 클래스는 하나의 공개 API가 되기 때문인데, 만약 이 클래스가 널리 퍼진다면 구현한 직렬화 형태도 영원히 지원해야 한다. 자바의 기본 직렬화 방식을 사용하면 직렬화 형태는 적용 당시 클래스의 내부 구현 방식에 종속된다. 달리 말하면, 클래스의 private와 package-private ..
자바에 직렬화가 도입되면서 프로그래머가 어렵지 않게 분산 객체를 만들 수 있게 되었지만, 심각한 보안 문제를 마주해야 했다. 자바 직렬화의 근본적인 문제 - 취약점 직렬화의 근본적인 문제는 공격 범위가 너무 넓고, 지속적으로 더 넓어지기 때문에 방어하기 어렵다는 점이다. ObjectInputStream의 readObject() 메서드는 Serializable 인터페이스를 구현한 클래스패스 안에 거의 모든 타입의 객체를 만들어 낼 수 있다. 바이트 스트림을 역직렬화하는 과정에서 이 메서드는 그 타입들 안의 모든 코드를 수행할 수 있고, 이로 인해 그 타입들의 코드 전체가 공격 범위에 들어가게 된다. (자바 표준 라이브러리와 서드 파티 라이브러리 등 모두 포함) 가능한 모든 모범 사례를 따르고 모든 직렬화 ..