CORS support in Spring Framework


CORS support in Spring Framework


이 글은 아래 원문의 저자의 허락을 맡고 번역한 글입니다.

원문 :  https://spring.io/blog/2015/06/08/cors-support-in-spring-framework



보안상의 이슈로, 브라우저에서 리소스를 현재 origin에서 다른곳으로의 AJAX  요청을 금하고 있다.
예를 들어, 브라우저 한쪽 탭에서 은행 계좌를 체크하고 다른 탭에서 evil.com 웹사이트를 접속하고 있다.
evil.com의 스크립트에서 credential을 이용해 은행 API로 AJAX 요청을 할 수 없다.

Cross-origin resource sharing(CORS)는 IFrame이나 JSONP와 같은 일부 보안에 약하거나 강력하지 않은 hack과 같은 방법 대신에 권한이 있는 도메인 간 요청을 유연한 방법으로 제공하는 대부분의 브라우저에서 구현된 W3C 사양이다.

Spring Framework 4.2 GA는 전형적인 filter 기반으로 해결하는 대신 좀 더 쉽고 강력한 방법으로 구성할 수 있는 CORS를 위한 클래스를 처음으로 제공한다.

Spring MVC는 높은 수준의 구성 기능을 제공한다.

Controller 메소드에 CORS 설정

@RequestMapping 어노테이션이 있는 handler 메소드에 @CrossOrigin 어노테이션을 달아 CORS를 활성화시킨다.(기본적으로  @CrossOrigin은 모든 origin과 @RequestMapping  어노테이션의 HTTP 메소드를 허용한다.)

@RestController
@RequestMapping("/account")
public class AccountController {

	@CrossOrigin
	@RequestMapping("/{id}")
	public Account retrieve(@PathVariable Long id) {
		// ...
	}

	@RequestMapping(method = RequestMethod.DELETE, value = "/{id}")
	public void remove(@PathVariable Long id) {
		// ...
	}
}

또한 전체 controller에 CORS를 활성화하는것도 가능하다.

@CrossOrigin(origins = "http://domain2.com", maxAge = 3600)
@RestController
@RequestMapping("/account")
public class AccountController {

	@RequestMapping("/{id}")
	public Account retrieve(@PathVariable Long id) {
		// ...
	}

	@RequestMapping(method = RequestMethod.DELETE, value = "/{id}")
	public void remove(@PathVariable Long id) {
		// ...
	}
}
이 예에서 CORS 지원은 핸들러 메소드인 retrieve()와 remove() 둘다 활성화하는것을 지원하고 @CrossOrigin 속성을 이용하여 CORS 을 커스터마이징을 할 수 있다.

컨트롤러나 메소드 레벨의 CORS 설정을 할 수 있고  Spring은 컨트롤러와 메소드에 둘 다 쓸수있는 CORS 설정을 생성하기 위한 어노테이션 속성을 만들것이다.

@CrossOrigin(maxAge = 3600)
@RestController
@RequestMapping("/account")
public class AccountController {

        @CrossOrigin(origins = "http://domain2.com")
        @RequestMapping("/{id}")
        public Account retrieve(@PathVariable Long id) {
                // ...
        }

        @RequestMapping(method = RequestMethod.DELETE, value = "/{id}")
        public void remove(@PathVariable Long id) {
                // ...
        }
}

Global CORS 설정

추가로 어노테이션 기반 설정뿐만 아니라 global CORS 설정을 정의하기를 원할 것이다.

이 방법은 filter를 사용하는것과 유사하지만 Spring MVC와 함께 선언할 수 있고 @CrossOrigin 설정과 함께 쓸수 있다. 기본적으로 모든 origin과 GET, HEAD와 POST 메소드가 허용된다.


JavaConfig

전체 어플리케이션에 CORS를 활성화하기 위해서는 다음과 같이 간단하다.

@Configuration
@EnableWebMvc
public class WebConfig extends WebMvcConfigurerAdapter {

        @Override
        public void addCorsMappings(CorsRegistry registry) {
                registry.addMapping("/**");
        }
}

어떤 속성이라도 쉽게 바꿀수 있고 특정 path 패턴에만 CORS 설정을 적용할 수 있다.
@Configuration
@EnableWebMvc
public class WebConfig extends WebMvcConfigurerAdapter {

        @Override
        public void addCorsMappings(CorsRegistry registry) {
                registry.addMapping("/api/**")
                        .allowedOrigins("http://domain2.com")
                        .allowedMethods("PUT", "DELETE")
                        .allowedHeaders("header1", "header2", "header3")
                        .exposedHeaders("header1", "header2")
                        .allowCredentials(false).maxAge(3600);
        }
}

XML 네임스페이스

mvc XML 네임스페이스로 CORS를 설정하는것도 가능하다.

JavaConfig 대신 default properties로 /** path 패턴으로 최소한의 XML 설정으로 CORS를 활성화할 수 있다.

<mvc:cors>
        <mvc:mapping path="/**" />
</mvc:cors>

또한 커스터마이스된 속성으로 몇가지 CORS 매핑을 정의할 수도 있다.

<mvc:cors>

        <mvc:mapping path="/api/**"
                allowed-origins="http://domain1.com, http://domain2.com"
                allowed-methods="GET, PUT"
                allowed-headers="header1, header2, header3"
                exposed-headers="header1, header2" allow-credentials="false"
                max-age="123" />

        <mvc:mapping path="/resources/**"
                allowed-origins="http://domain1.com" />

</mvc:cors>


어떻게 동작하는가?

CORS 요청은(OPTIONS 메소드로 preflight를 포함한) 자동으로 다양하게 등록된 HandlerMapping을 dispatch한다.
CORS 응답 요청(Access-Control-Allow-Origin과 같은)을 추가하기 위해 CorsProcessor 구현(기본적으로 DefaultCorsProcessor) 에 CORS preflight 요청을 처리하고 CORS를 가로채서 간단하고 실제 요청을 감사를 처리한다.

CorsConfiguration 은 CORS요청이 어떻게 허용 origin, 헤더, 메소드등 처리되어야하는지 방법을 지정할 수 있다.
이것은 다양한 방법으로 제공된다.



  • 하위 클래스들은  AbstractHandlerMapping#getCorsConfiguration(Object, HttpServletRequest) 메소드를 오버라이딩해서 고유 CorsConfiguration을 제공한다


Spring Boot integration

CORS는 Spring Boot 1.3 release 에서 사용가능할 것이고, 1.3.0.BUILD-SNAPSHOT 빌드에서 이미 사용가능하다.

Spring Boot application에서 특별히 어떤 설정도 하지 않고, Controller 메소드에 @CrossOrigin 어노테이션으로 CORS 설정을 사용할 수 있다.

Global CORS 설정은 커스터마이징된 addCorsMappings(CorsRegistry)메소드의 빈 WebMvcConfigurer 을 등록함으로써 정의된다.

@Configuration
public class MyConfiguration {

    @Bean
    public WebMvcConfigurer corsConfigurer() {
        return new WebMvcConfigurerAdapter() {
            @Override
            public void addCorsMappings(CorsRegistry registry) {
                registry.addMapping("/api/**");
            }
        };
    }
}





저작자 표시 비영리 변경 금지
신고

'Framework > SpringFramework' 카테고리의 다른 글

CORS support in Spring Framework  (0) 2015.11.09
리버 Jazzit
Framework/SpringFramework 2015.11.09 22:00

Java 8 Features - The ULTIMATE Guide


이 글은 원문의 저자와 글을 게시한 Java Code Geeks의 허락을 맡고 번역한 글입니다.



편집 노트 : 모든 점에서 정말 주요한 Java 8의 release 된지 꽤 되었다. Java Code Geeks 에서는 Playing with Java 8 – Lambdas and ConcurrencyJava 8 Date Time API Tutorial : LocalDateTime 그리고 Abstract Class Versus Interface in the JDK 8 Era과 같은 풍부한 튜토리얼을 제공하고 있다.

또한 다른 링크에서 참고자료로 15 Must Read Java 8 Tutorials가 있다. 물론, The Dark Side of Java 8과 같은 자바의 부족한 점도 설명하고 있다.

이제, 당신의 읽는 즐거움을 위한 하나의 참고용 포스팅으로 주요 Java 8 기능을 살펴보는 시간이다. Enjoy!

Table Of Contents

1. Introduction
2. New Features in Java language
2.1. Lambdas and Functional Interfaces
2.2. Interface Default and Static Methods
2.3. Method References
2.4. Repeating annotations
2.5. Better Type Inference
2.6. Extended Annotations Support
3. New Features in Java compiler
3.1. Parameter names
4. New Features in Java libraries
4.1. Optional
4.2. Streams
4.3. Date/Time API (JSR 310)
4.4. Nashorn JavaScript engine
4.5. Base64
4.6. Parallel Arrays
4.7. Concurrency
5. New Java tools
5.1. Nashorn engine: jjs
5.2. Class dependency analyzer: jdeps
6. New Features in Java runtime (JVM)
7. Conclusions
8. Resources


1. 소개

의심할 여지없이, Java 8 release는 Java5 (꽤 오래전인 2004년에 release되었다)이후 자바에서 가장 큰 변화이다. Java 8은 언어, 컴파일러, 라이브러리, 툴 그리고 JVM등으로써 많은 새로운 기능을 가져왔다.
이 튜토리얼에서 우리는 실제 예제들에서 시나리오를 이용한 다른 데모들을 살펴볼것이다.
 
이 튜토리얼은 플랫폼의 특정 부분을 살펴보는 여러 파트로 구성되어있다.
  • language
  • compiler
  • libraries
  • tools
  • runtime (JVM)

2. 자바 언어의 새로운 기능

Java 8은 어떠한 측면에서 보아도 주요한 release이다. 모든 자바 개발자들이 찾고 있던 기능을 구현하기 위한 마무리를 하기까지 너무 오래걸렸다. 이 섹션에서 그 부분을 대부분 커버할 것이다.


2.1 람다(Lambda)와 함수형 인터페이스(Functional Interfaces)

람다(closures라고도 알려짐)의 전체 Java 8 release에서 가장 크고 가장 많이 기다려온 언어의 변화이다.
람다는 우리가 메소드 argument를 함수로 처리하던지, 아니면 데이터를 코드로 처리하도록 허용해준다. 이 컨셉은 모든 functional 개발자에게 매우 친숙하다.
JVM 플랫폼의 많은 언어들(Groovy, Scala…)은 처음부터 람다를 지원했지만, 자바 개발자는 익명 클래스(anonymous class)를 쓰는것말고는 선택의 여지가 없었다.

람다 설계를 토론하는데 시간이 오래걸리고 커뮤니티의 노력도 많이 들었다. 하지만 마침내 절충안을 찾았고, 새로운 간결함과 치밀한 언어 구성을 가져왔다. 
람다의 가장 간단한 형식은, 람다는 -> 표시와 구현으로 파라미터의 콤마로 구분된 리스트로 표현될수 있다.  예를 들어 :

1Arrays.asList( "a""b""d" ).forEach( e -> System.out.println( e ) );

argument의 e의 타입은 컴파일러에 의해 추론된다. 아니면 괄호안에 정의하여 명시적으로 파라미터의 타입을 제공해도 된다. 예를 들어 : 

1Arrays.asList( "a""b""d" ).forEach( ( String e ) -> System.out.println( e ) );

다음 경우의 람다의 구현은 더욱 복잡한데, 자바에서 보통 function을 정의하는것과 같이 중괄호 { 로 감싸도 된다. 예를 들어 : 

1Arrays.asList( "a""b""d" ).forEach( e -> {
2    System.out.print( e );
3    System.out.print( e );
4} );

람다는 클래스의 멤버와 지역 변수(명시적으로 final을 선언해서)를 참조할 수 있다. 예를 들어, 다음 두 코드는 동일하다.

1String separator = ",";
2Arrays.asList( "a""b""d" ).forEach(
3    ( String e ) -> System.out.print( e + separator ) );


그리고

1final String separator = ",";
2Arrays.asList( "a""b""d" ).forEach(
3    ( String e ) -> System.out.print( e + separator ) );

람다는 값을 리턴할 수도 있다. 리턴값의 타입은 컴파일러에 의해 추론될 것이다. 만약 람다의 구현이 단 한줄이라면 return 문은 필요하지 않다. 
아래 두 코드는 동일하다.

1Arrays.asList( "a""b""d" ).sort( ( e1, e2 ) -> e1.compareTo( e2 ) );


그리고

1Arrays.asList( "a""b""d" ).sort( ( e1, e2 ) -> {
2    int result = e1.compareTo( e2 );
3    return result;
4} );


언어를 설계한 사람은 어떻게 이미 존재하는 람다를 함수적으로 친숙하게 만들지에 대해 많은 생각을 하였다. 그 결과, functional interfaces의 컨셉이 등장했다.
function interface는 하나의 메소드를 가진 인터페이스이다. 이것은 암묵적으로 람다 표현식으로 변환될것이다. java.lang.Runnable과 java.util.concurrent.Callable 은 functional interface의 두가지  좋은 예이다.
실제로, functional interface는 깨지기 쉽다 : 만약 누군가가 인터페이스에 다른 메소드를 정의하면, 이 인터페이스는 더이상 functional 하지 않고 컴파일 과정은 실패할 것이다.
이렇게 취약점을 극복하기 위해 functional로 java 8에 특별한 @FunctionalInterface 어노테이션을 추가하여 인터페이스의 의도를 명쾌하게 정의한다. 간단한 functional 인터페이스 정의를 살펴보자.

1@FunctionalInterface
2public interface FunctionalDefaultMethods {
3    void method();



한가지 명심하라: default와 static 메소드는 functional interface 규약를 깨지않고 선언된다.

1@FunctionalInterface
2public interface FunctionalDefaultMethods {
3    void method();
4         
5    default void defaultMethod() {           
6    }       
7}

람다는 Java 8의 가장 큰 장점이다. 람다는 이 훌륭한 플랫폼에 잠재적으로 개발자들을 점점 끌어들이고 순수 Java에서 functional 프로그래밍 컨셉을 위한 art 지원의 상태를 제공한다.
더 자세히 알고 싶다면 official documentation을 참고하라.


2.2 Inteface의 Default와 Static Method

Java 8 은 default와 static 메소드 두가지 컨셉으로 interface 선언으로 상속한다. Default methods는 조금 다른 목표를 제공하지만 trait을 쓰는것과 비슷하게 interface를 만든다.
Default 메소드는 이 interface의 이전 버전에 작성된 코드의 바이너리 호환을 깨지 않는 존재하는 interface에 새로운 메소드 추가를 허용한다.
default 메소드와 abstract 메소드의 차이점은 abstract 메소드는 구현이 되어져야한다. 하지만 default 메소드는 아니다. 대신에, 각 interface는 default 구현과 default에 의해 상속한 구현체들(만약 필요하면 이 default 구현을 오버라이드하기 위해 가능한)이 호출되도록 제공해야한다. 아래의 예제를 살펴보자.

01private interface Defaulable {
02    // Interfaces now allow default methods, the implementer may or
03    // may not implement (override) them.
04    default String notRequired() {
05        return "Default implementation";
06    }       
07}
08         
09private static class DefaultableImpl implements Defaulable {
10}
11     
12private static class OverridableImpl implements Defaulable {
13    @Override
14    public String notRequired() {
15        return "Overridden implementation";
16    }
17}

Defaulable interface는 메소드 정의의 일부분으로 키워드 default를 사용하여 default 메소드인 notRequired()를 선언한다. 클래스들중의 하나인 DefaultableImpl은 있는 그대로의 default 메소드 구현을 떠나 interface를 구현한다.
다른 클래스인 OverridableImpl 는 default 구현과 그것을 제공한 구현을 오버라이드한다.

Java 8에 또다른 흥미로운 기능은 interface를 static 메소드로 정의(그리고 구현체를 제공)할 수 있다. 예를 보자.

1private interface DefaulableFactory {
2    // Interfaces now allow static methods
3    static Defaulable create( Supplier< Defaulable > supplier ) {
4        return supplier.get();
5    }
6}


아래 코드는 위의 예의 default 메소드와 static 메소드를 함께 쓰는 예제이다. 

1public static void main( String[] args ) {
2    Defaulable defaulable = DefaulableFactory.create( DefaultableImpl::new );
3    System.out.println( defaulable.notRequired() );
4         
5    defaulable = DefaulableFactory.create( OverridableImpl::new );
6    System.out.println( defaulable.notRequired() );
7}


위의 예제의 결과를 보면 다음과 같다.

1Default implementation
2Overridden implementation

JVM에서 default 메소드 구현은 매우 효율적이고 메소드 호출을 위한 바이트 코드 명령을 지원한다. default 메소드는 컴파일 과정을 깨지않고 발전하기위해 Java interface가 존재하는것을 허용한다.
이 좋은 예는 java.util.Collection interface: stream()parallelStream()forEach()removeIf(), …에 추가된 메소드에서 많이 볼 수 있다.

default 메소드가 강력하지만 주의해서 사용되어야한다. : default 메소드는 복잡한 계층구조에서 모호성과 컴파일 에러를 초래할 수 있기 때문에 default 메소드를 선언하기 전에 만약 정말 필요한지 두번 생각해봐야한다.
더 자세한 내용은 official documentation 여기에서 확인해볼것.


2.3 메소드 레퍼런스(Method References)

메소드 레퍼런스는 Java 클래스나 객체(instance)에 존재하는 메소드나 생성자에 직접 참조하기 위한 유용한 문법을 제공한다. 람다 표현식의 결합과 메소드 참조는 표준규약을 떠나 언어를 탄탄하고 간결하게 만들어지도록 만든다.

래, Car 클래스를 메소드 레퍼런스의 타입을 지원하는 4개의 다른 메소드로 정의한 예를 보자.

01public static class Car {
02    public static Car create( final Supplier< Car > supplier ) {
03        return supplier.get();
04    }             
05         
06    public static void collide( final Car car ) {
07        System.out.println( "Collided " + car.toString() );
08    }
09         
10    public void follow( final Car another ) {
11        System.out.println( "Following the " + another.toString() );
12    }
13         
14    public void repair() {  
15        System.out.println( "Repaired " this.toString() );
16    }
17}

메소드 레퍼런스의 첫번째 타입은 Class::new 나 제네릭을 이용한 Class< T >::new의 문법으로 된 생성자이다. 참고로 생성자 argument가 없다. 

1final Car car = Car.create( Car::new );
2final List< Car > cars = Arrays.asList( car );

메소드 레퍼런스의 두번째 타입은 Class::static_method 로 된 static 메소드이다. Car의 타입은 이 메소드는 정확히 하나의 파라미터만 허용한다. 

1cars.forEach( Car::collide );

메소드 레퍼런스의 세번째 타입은 Class::method로 된 특정 타입의 임의 객체의 instance 메소드이다. 메소드는 argument가 없는것만 허용한다.

1cars.forEach( Car::repair );

마지막으로, 네번째 타입은 instance::method로 된 특정 클래스 instance의 메소드를 instance하기 위한 것이다. Car 타입이 정확히 하나의 파라미터만 서용하는 메소드이다.

1final Car police = Car.create( Car::new );
2cars.forEach( police::follow );

이 예제들을 실행시키고 console의 결과를 보면 다음과 같다(실제 Car 인스턴스들은 다르다)

1Collided com.javacodegeeks.java8.method.references.MethodReferences$Car@7a81197d
2Repaired com.javacodegeeks.java8.method.references.MethodReferences$Car@7a81197d
3Following the com.javacodegeeks.java8.method.references.MethodReferences$Car@7a81197d

메소드 레퍼런스에 대해 더 알고 싶다면 official documentation.


2.4 반복 annotations
 
Java 5부터 지원된 annotation은 점점 인기를 더해가고 더 널리 쓰여지고 있다. 하지만 annotation 사용의 제한사항중의 하나는 같은 위치에 하나 이상의 같은 annotation을 선언할 수 없다는 것이었다.
Java 8은 이 규칙을 깨고 반복하는 annotation을 소개했다. 같은 위치에 annotation을 여러번 반복해 선언해 쓸수있다.

반복적인 annotation을 사용하기 위해서는 @Repeatable annotation으로 지정되어야한다. 사실 이건 언어의 변경이 아니고 같은 기술로 컴파일러 트릭에  가깝다.
예제를 살펴보자.

01package com.javacodegeeks.java8.repeatable.annotations;
02 
03import java.lang.annotation.ElementType;
04import java.lang.annotation.Repeatable;
05import java.lang.annotation.Retention;
06import java.lang.annotation.RetentionPolicy;
07import java.lang.annotation.Target;
08 
09public class RepeatingAnnotations {
10    @Target( ElementType.TYPE )
11    @Retention( RetentionPolicy.RUNTIME )
12    public @interface Filters {
13        Filter[] value();
14    }
15     
16    @Target( ElementType.TYPE )
17    @Retention( RetentionPolicy.RUNTIME )
18    @Repeatable( Filters.class )
19    public @interface Filter {
20        String value();
21    };
22     
23    @Filter"filter1" )
24    @Filter"filter2" )
25    public interface Filterable {       
26    }
27     
28    public static void main(String[] args) {
29        for( Filter filter: Filterable.class.getAnnotationsByType( Filter.class ) ) {
30            System.out.println( filter.value() );
31        }
32    }
33}

예에서 보듯이 @Repeatable( Filters.class )이라고 annotation지정이 되어있는 Filter annotation클래스가 있다.
이  Filters는 Filter annotation을 가지고 있지만 자바 컴파일러는 개발자에게 이 존재를 숨기려고 한다.
Filterable 인터페이스는 Filter annotation을 두번 선언했다.(Filters의 언급한것 없이)

Reflection API는 어떤 타입의 반복적인 annotation을 반환하기 위한 새로운 메소드 getAnnotationsByType()를 제공한다.(Filterable.class.getAnnotation( Filters.class ) 은 컴파일러에 의해 주입된(injected) Filters의 인스턴스를 반환할것이다.)

예제의 출력은 다음과 같다.:

1filter1
2filter2

더 자세히 알고싶다면 official documentation.


2.5 더 발전된 타입 추론 (Better Type Inference)


Java 8 컴파일러는 타입 추론이 많이 향상되었다. 많은 경우가 명시적으로 타입 파라미터가 깔끔한 코드를 유지하기 위해 컴파일러에 의해 추론될 수 있다. 
그런 경우를 다음 예를 살펴보자.

01package com.javacodegeeks.java8.type.inference;
02 
03public class Value< T > {
04    public static< T > T defaultValue() {
05        return null;
06    }
07     
08    public T getOrDefault( T value, T defaultValue ) {
09        return ( value != null ) ? value : defaultValue;
10    }
11}


Value< String > 타입을 쓰는 예는 다음과 같다.


1package com.javacodegeeks.java8.type.inference;
2 
3public class TypeInference {
4    public static void main(String[] args) {
5        final Value< String > value = new Value<>();
6        value.getOrDefault( "22", Value.defaultValue() );
7    }
8}

Value.defaultValue()의 타입 파라미터는 추론되고 provide되기 위해 꼭 필요하진 않는다. Java 7에서 같은 예제는 컴파일 되지 않을것이고 Value.< String >defaultValue()로 재작성되어야한다.


2.6 확장된 Annotation 지원(Extended Annotations Support)

Java 8은 annotation이 쓰이는 곳에 context를 상속한다. 지역 변수, 제네릭 타입, 수퍼클래스와 인터페이스 구현체, 또한 메소드 exception 정의까지 거의 모든것을 annotation할 수 있다.
아래 몇가지 예를 살펴보자.

01package com.javacodegeeks.java8.annotations;
02 
03import java.lang.annotation.ElementType;
04import java.lang.annotation.Retention;
05import java.lang.annotation.RetentionPolicy;
06import java.lang.annotation.Target;
07import java.util.ArrayList;
08import java.util.Collection;
09 
10public class Annotations {
11    @Retention( RetentionPolicy.RUNTIME )
12    @Target( { ElementType.TYPE_USE, ElementType.TYPE_PARAMETER } )
13    public @interface NonEmpty {       
14    }
15         
16    public static class Holder< @NonEmpty T > extends @NonEmpty Object {
17        public void method() throws @NonEmpty Exception {          
18        }
19    }
20         
21    @SuppressWarnings"unused" )
22    public static void main(String[] args) {
23        final Holder< String > holder = new @NonEmpty Holder< String >();      
24        @NonEmpty Collection< @NonEmpty String > strings = new ArrayList<>();      
25    }
26}

ElementType.TYPE_USE 와 ElementType.TYPE_PARAMETER 두개의 새로운 엘리먼트 타입은 적용되는 annotation 컨텍스트를 설명하기 위한것이다.
Annotation Processing API는 자바 프로그래밍 언어에서 새로운 타입 annotation을 인식하기 위한 minor한 변경이 되었다 


3. 자바 컴파일러의 새로운 기능(New Features in Java compiler)

3.1 파라미터 이름

자바 개발자는 자바 바이트코드에서 메소드 파라미터 이름(method parameter names in Java byte-code)을 보존하고 런타임시에 사용가능하도록(예를 들어, Paranamer library) 하기 위한 다양한 방법을 발전시켜왔다.  
그리고 마침내 Java 8은 이같은 요구 기능이 언어(Reflection API와 Parameter.getName() 메소드) 바이트코드(새로운 javac 컴파일러 argument -parameters) 에서 지원한다.

01package com.javacodegeeks.java8.parameter.names;
02 
03import java.lang.reflect.Method;
04import java.lang.reflect.Parameter;
05 
06public class ParameterNames {
07    public static void main(String[] args) throws Exception {
08        Method method = ParameterNames.class.getMethod( "main", String[].class );
09        forfinal Parameter parameter: method.getParameters() ) {
10            System.out.println( "Parameter: " + parameter.getName() );
11        }
12    }
13}


만약 -parameters 없이 클래스를 컴파일하고 프로그램 실행을 하면, 다음과 같은 결과를 볼 것이다.

1Parameter: arg0

-parameters argument는 컴파일러에게 전달하고 프로그램의 출력결과는 달라질 것이다(파라미터의 실제 이름이 보여질것이다)

1Parameter: args

Maven 사용자는 maven-compiler-plugin의 configration 부분에 컴파일러 –parameters argument를 추가해주면 된다.

01<plugin]] >
02    <groupId>org.apache.maven.plugins</groupId]] >
03    <artifactId>maven-compiler-plugin</artifactId]] >
04    <version>3.1</version]] >
05    <configuration]] >
06        <compilerArgument>-parameters</compilerArgument]] >
07        <source>1.8</source]] >
08        <target>1.8</target]] >
09    </configuration]] >
10</plugin]] >

Java8과 함께 release된 Eclipse Kepler SR2((please check out this download instructions) 는 아래 그림과 같이 compiler setting에 configuration 옵션으로 제공되도록 지원한다.

Picture 1. Configuring Eclipse projects to support new Java 8 compiler –parameters argument.

Picture 1. Configuring Eclipse projects to support new Java 8 compiler –parameters argument.


추가로, 파라미터 이름의 유효성을 확인하기 위해서는 Parameter 클래스에 제공된 유용한 메소드인 isNamePresent()를 이용하라.


4. 자바 라이브러리의 새로운 기능

Java 8은 concurrency, 함수형 프로그래밍, date/time 등등의 더 많은 지원을 제공하기 위해 많은 새로운 클래스 추가하고 기존 클래스를 상속을 하였다.


4.1 Optional

지금까지 자바 어플리케이션의 실패중 가장 많은 원인을 초래하는 것이 NullPointerException이다. 오래전에 NullPointerExceptions의 해결책으로 Optional이 Google Guava 에서 소개되었고, null 체크로 코드상의 오염으로 낙담하는 개발자들에게 더 깔끔한 코드를 짤수있도록 고무시켰다. Google Guava에서 영감을 받아, Optional 은 자바 라이브러리의 일부분이 되었다.
Optional 은 단순한 컨테이너이다: 어떤 타입 T의 value를 담거나 단순히 null을 담는다. Optional 은 많은 유용한 메소드를 제공하고 더이상 명시적인 null  체크를 할 필요가 없다.
더 자세한 내용은 official Java 8 documentation 에서 참고하자.

Optional 의 사용법을 nullable value와 null을 허용하지 않는 value 두 예제에서 살펴볼것이다: 

1Optional< String > fullName = Optional.ofNullable( null );