while(1) work();
반응형

Spring 표현 언어(SpEL)

Spring 표현 언어(줄여서 "SpEL")는 런타임에 객체 그래프를 쿼리하고 조작하는 것을 지원하는 강력한 표현 언어입니다. 언어 구문은 Jakarta 표현 언어와 유사하지만 메서드 호출과 기본 문자열 템플릿 기능 등 추가 기능을 제공합니다.

OGNL, MVEL, JBoss EL 등 여러 가지 다른 Java 표현 언어가 있지만, Spring 표현 언어는 Spring 포트폴리오의 모든 제품에서 사용할 수 있는 잘 지원되는 단일 표현 언어를 Spring 커뮤니티에 제공하기 위해 만들어졌습니다. 이 언어의 기능은 Spring 도구용 이클립스 내에서 코드 완성 지원을 위한 도구 요구 사항을 포함하여 Spring 포트폴리오에 포함된 프로젝트의 요구 사항에 따라 결정됩니다. 즉, SpEL은 기술 독립적인 API를 기반으로 하므로 필요한 경우 다른 표현식 언어 구현을 통합할 수 있습니다.

SpEL은 Spring 포트폴리오 내에서 표현식 평가의 기반 역할을 하지만, Spring과 직접적으로 연결되어 있지 않으며 독립적으로 사용할 수 있습니다. 독립적으로 사용하기 위해 이 장의 많은 예제에서는 SpEL을 마치 독립적인 표현식 언어처럼 사용합니다. 이를 위해서는 파서와 같은 몇 가지 부트스트랩 인프라 클래스를 만들어야 합니다. 대부분의 Spring 사용자는 이러한 인프라를 처리할 필요가 없으며 대신 평가를 위한 표현식 문자열만 작성할 수 있습니다. 이러한 일반적인 사용의 예는빈 정의 정의에 대한 표현식 지원에서 볼 수 있듯이 XML 또는 주석 기반 빈 정의를 생성하는 데 SpEL을 통합하는 것입니다.

이 장에서는 표현식 언어의 기능, API 및 언어 구문에 대해 다룹니다. 여러 곳에서 표현식 평가를 위한 대상 객체로 Inventor  Society 클래스가 사용됩니다. 이러한 클래스 선언과 이를 채우는 데 사용되는 데이터는 이 장의 마지막에 나열되어 있습니다.

표현식 언어는 다음과 같은 기능을 지원합니다:

  • 리터럴 표현식
  • 속성, 배열, 목록 및 맵에 액세스하기
  • 인라인 목록
  • 인라인 맵
  • 배열 구성
  • 관계형 연산자
  • 정규 표현식
  • 논리 연산자
  • 문자열 연산자
  • 수학 연산자
  • 할당
  • 유형 표현식
  • 메서드 호출
  • 생성자 호출
  • 변수
  • 사용자 정의 함수
  • 빈 참조
  • 삼항식, 엘비스 및 안전 탐색 연산자
  • 컬렉션 투영
  • 컬렉션 선택
  • 템플릿 표현식

 

Evaluation

이 섹션에서는 SpEL의 인터페이스와 표현식 언어를 프로그래밍 방식으로 사용하는 방법을 소개합니다. 전체 언어 참조는언어 참조에서 확인할 수 있습니다.

다음 코드는 SpEL API를 사용하여 리터럴 문자열 표현식 Hello World를 평가하는 방법을 보여줍니다.

ExpressionParser parser = new SpelExpressionParser();
Expression exp = parser.parseExpression("'Hello World'"); 
String message = (String) exp.getValue();
  메시지 변수의 값은 "Hello World"입니다.

가장 많이 사용하는 SpEL 클래스와 인터페이스는org.springframework.expression 패키지와 그 하위 패키지(예: spel.support)에 있습니다.

ExpressionParser 인터페이스는 표현식 문자열 구문 분석을 담당합니다. 앞의 예제에서 표현식 문자열은 주변 작은따옴표로 표시된 문자열 리터럴입니다. Expression 인터페이스는 정의된 표현식 문자열의 평가를 담당합니다.Parser.parseExpression(...)  exp.getValue(... )를 호출할 때 발생할 수 있는 두 가지 유형의 예외는 각각 ParseException과EvaluationException입니다.

SpEL은 메서드 호출, 속성 액세스, 생성자 호출과 같은 다양한 기능을 지원합니다.

다음 메서드 호출 예제에서는 문자열 리터럴인 Hello World에서 concat 메서드를 호출합니다.

ExpressionParser parser = new SpelExpressionParser();
Expression exp = parser.parseExpression("'Hello World'.concat('!')"); 
String message = (String) exp.getValue();
  이제 메시지 값은 "Hello World!"가 됩니다.

다음 예제는 문자열 리터럴인 Hello World의 Bytes JavaBean 프로퍼티에 액세스하는 방법을 보여줍니다.

ExpressionParser parser = new SpelExpressionParser();

// invokes 'getBytes()'
Expression exp = parser.parseExpression("'Hello World'.bytes"); 
byte[] bytes = (byte[]) exp.getValue();
  이 줄은 리터럴을 바이트 배열로 변환합니다.

SpEL은 표준 점 표기법(예:prop1.prop2.prop3)과 해당 속성 값 설정을 사용하여 중첩된 속성도 지원합니다. 공개 필드에도 액세스할 수 있습니다.

다음 예는 점 표기법을 사용하여 문자열 리터럴의 길이를 구하는 방법을 보여줍니다.

ExpressionParser parser = new SpelExpressionParser();

// invokes 'getBytes().length'
Expression exp = parser.parseExpression("'Hello World'.bytes.length"); 
int length = (Integer) exp.getValue();
  'Hello World'.bytes.length는 리터럴의 길이를 반환합니다.

다음 예제에서 볼 수 있듯이 문자열 리터럴을 사용하는 대신 문자열의 생성자를 호출할 수 있습니다.

ExpressionParser parser = new SpelExpressionParser();
Expression exp = parser.parseExpression("new String('hello world').toUpperCase()"); 
String message = exp.getValue(String.class);
  리터럴에서 새 문자열을 생성하고 대문자로 변환합니다.

일반 메서드 사용에 유의하세요: public <T> T getValue(Class<T> desiredResultType). 이 메서드를 사용하면 표현식 값을 원하는 결과 유형으로 캐스팅할 필요가 없습니다. 값을 T 유형으로 캐스팅할 수 없거나 등록된 유형 변환기를 사용하여 변환할 수 없는 경우 EvaluationException이 throw됩니다.

SpEL의 더 일반적인 용도는 특정 객체 인스턴스(루트 객체라고 함)에 대해 평가되는 표현식 문자열을 제공하는 것입니다. 다음 예는 Inventor 클래스의 인스턴스에서 이름 속성을 검색하는 방법과 부울 표현식에서 이름 속성을 참조하는 방법을 보여줍니다.

// Create and set a calendar
GregorianCalendar c = new GregorianCalendar();
c.set(1856, 7, 9);

// The constructor arguments are name, birthday, and nationality.
Inventor tesla = new Inventor("Nikola Tesla", c.getTime(), "Serbian");

ExpressionParser parser = new SpelExpressionParser();

Expression exp = parser.parseExpression("name"); // Parse name as an expression
String name = (String) exp.getValue(tesla);
// name == "Nikola Tesla"

exp = parser.parseExpression("name == 'Nikola Tesla'");
boolean result = exp.getValue(tesla, Boolean.class);
// result == true

Understanding EvaluationContext

EvaluationContext 인터페이스는 표현식을 평가하여 속성, 메서드 또는 필드를 확인하고 유형 변환을 수행할 때 사용됩니다. Spring은 두 가지 구현을 제공합니다.

  • SimpleEvaluationContext: SpEL 언어 구문의 전체 범위가 필요하지 않고 의미 있게 제한되어야 하는 표현식 범주에 대해 필수 SpEL 언어 기능 및 구성 옵션의 하위 집합을 노출합니다. 예를 들면 데이터 바인딩 표현식과 속성 기반 필터 등이 있지만 이에 국한되지 않습니다.
  • 표준 평가 컨텍스트: SpEL 언어 기능 및 구성 옵션의 전체 집합을 노출합니다. 이를 사용하여 기본 루트 객체를 지정하고 사용 가능한 모든 평가 관련 전략을 구성할 수 있습니다.

SimpleEvaluationContext는 SpEL 언어 구문의 하위 집합만 지원하도록 설계되었습니다. Java 유형 참조, 생성자 및 빈 참조는 제외됩니다. 또한 표현식에서 프로퍼티 및 메서드의 지원 수준을 명시적으로 선택해야 합니다. 기본적으로 create() 정적 팩토리 메서드는 프로퍼티에 대한 읽기 액세스만 허용합니다. 다음 중 하나 또는 일부 조합을 대상으로 필요한 정확한 지원 수준을 구성하는 빌더를 가져올 수도 있습니다.

  • 사용자 지정 속성 접근 자만(리플렉션 없음)
  • 읽기 전용 액세스를 위한 데이터 바인딩 속성
  • 읽기 및 쓰기용 데이터 바인딩 속성

유형 변환

기본적으로 SpEL은 Spring 코어에서 사용할 수 있는 변환 서비스(org.springframework.core.convert.ConversionService)를 사용합니다. 이 변환 서비스는 일반적인 변환을 위한 많은 기본 제공 변환기와 함께 제공되지만, 유형 간에 사용자 정의 변환을 추가할 수 있도록 완전히 확장 가능합니다. 또한 제네릭을 인식합니다. 즉, 표현식에서 제네릭 유형으로 작업할 때 SpEL은 발견되는 모든 객체에 대해 유형 정확성을 유지하기 위해 변환을 시도합니다.

이것이 실제로 무엇을 의미할까요? SetValue()를 사용하는 대입이 List 속성을 설정하는 데 사용된다고 가정해 보겠습니다. 이 프로퍼티의 유형은 실제로 List<Boolean>입니다. SpEL은 목록의 요소를 목록에 배치하기 전에 부울로 변환해야 한다는 것을 인식합니다. 다음 예제는 이를 수행하는 방법을 보여줍니다.

class Simple {
	public List<Boolean> booleanList = new ArrayList<>();
}

Simple simple = new Simple();
simple.booleanList.add(true);

EvaluationContext context = SimpleEvaluationContext.forReadOnlyDataBinding().build();

// "false" is passed in here as a String. SpEL and the conversion service
// will recognize that it needs to be a Boolean and convert it accordingly.
parser.parseExpression("booleanList[0]").setValue(context, simple, "false");

// b is false
Boolean b = simple.booleanList.get(0);

Parser Configuration

구문 분석기 구성 객체(org.springframework.expression.spel.SpelParserConfiguration)를 사용하여 SpEL 표현식 구문 분석기를 구성할 수 있습니다. 구성 객체는 일부 표현식 구성 요소의 동작을 제어합니다. 예를 들어 배열이나 컬렉션으로 인덱싱할 때 지정된 인덱스에 있는 요소가 null인 경우 SpEL은 자동으로 해당 요소를 생성할 수 있습니다. 이 기능은 일련의 속성 참조로 구성된 표현식을 사용할 때 유용합니다. 배열 또는 목록에 인덱싱하고 배열 또는 목록의 현재 크기 끝을 넘어서는 인덱스를 지정하면 SpEL은 해당 인덱스를 수용하도록 배열 또는 목록을 자동으로 늘릴 수 있습니다. 지정된 인덱스에 요소를 추가하기 위해 SpEL은 지정된 값을 설정하기 전에 요소 유형의 기본 생성자를 사용하여 요소를 생성하려고 시도합니다. 요소 유형에 기본 생성자가 없는 경우 배열 또는 목록에 null이 추가됩니다. 값을 설정하는 방법을 알고 있는 기본 제공 또는 사용자 정의 변환기가 없는 경우 지정된 인덱스의 배열 또는 목록에 null이 남아 있습니다. 다음 예는 목록을 자동으로 늘리는 방법을 보여줍니다.

class Demo {
	public List<String> list;
}

// Turn on:
// - auto null reference initialization
// - auto collection growing
SpelParserConfiguration config = new SpelParserConfiguration(true, true);

ExpressionParser parser = new SpelExpressionParser(config);

Expression expression = parser.parseExpression("list[3]");

Demo demo = new Demo();

Object o = expression.getValue(demo);

// demo.list will now be a real collection of 4 entries
// Each entry is a new empty String

기본적으로 SpEL 표현식은 10,000자를 초과하여 포함할 수 없지만maxExpressionLength는 구성할 수 있습니다. 프로그래밍 방식으로 SpelExpressionParser를생성하는 경우, SpelExpressionParser에 제공하는SpelParserConfiguration을 생성할 때 사용자 지정 maxExpressionLength를 지정할 수 있습니다. XML 빈 정의, @Value 등과 같이ApplicationContext내에서 SpEL 표현식을 구문 분석하는 데 사용되는 maxExpressionLength를 설정하려는 경우, JVM 시스템 속성 또는 spring.context.expression.maxLength라는Spring 속성을 애플리케이션에 필요한 최대 표현식 길이로 설정할 수 있습니다(지원되는 Spring 속성 참조).

SpEL Compilation

Spring은 SpEL 표현식을 위한 기본 컴파일러를 제공합니다. 표현식은 일반적으로 해석되므로 평가 중에 많은 동적 유연성을 제공하지만 최적의 성능을 제공하지는 않습니다. 가끔씩 표현식을 사용하는 경우에는 괜찮지만, Spring 통합과 같은 다른 컴포넌트에서 사용할 때는 성능이 매우 중요할 수 있으며 동적 유연성이 실제로 필요하지 않을 수 있습니다.

SpEL 컴파일러는 이러한 요구를 해결하기 위한 것입니다. 평가하는 동안 컴파일러는 런타임에 표현식 동작을 구현하는 Java 클래스를 생성하고 해당 클래스를 사용하여 훨씬 빠른 표현식 평가를 달성합니다. 표현식에 대한 타이핑이 없기 때문에 컴파일러는 컴파일을 수행할 때 표현식의 해석된 평가 중에 수집된 정보를 사용합니다. 예를 들어, 컴파일러는 표현식만으로는 속성 참조의 유형을 알 수 없지만, 첫 번째 해석된 평가 중에 그 유형이 무엇인지 알아냅니다. 물론 이렇게 파생된 정보를 기반으로 컴파일을 수행하면 시간이 지나면서 다양한 표현식 요소의 유형이 변경되는 경우 나중에 문제가 발생할 수 있습니다. 이러한 이유로 컴파일은 반복되는 평가에서 유형 정보가 변경되지 않는 표현식에 가장 적합합니다.

다음 기본 표현식을 고려해 보세요.

someArray[0].someProperty.someOtherProperty < 0.1

앞의 표현식은 배열 액세스, 일부 속성 참조 해제, 숫자 연산을 포함하므로 성능 향상이 매우 눈에 띄게 나타날 수 있습니다. 50,000회 반복의 마이크로 벤치마크 실행 예제에서 인터프리터를 사용하여 평가하는 데 75ms가 걸린 반면, 컴파일된 버전의 식을 사용하면 3ms밖에 걸리지 않았습니다.

컴파일러 구성

컴파일러는 기본적으로 켜져 있지 않지만 두 가지 방법 중 하나로 컴파일러를 켤 수 있습니다.앞서 설명한 파서 구성 프로세스를 사용하거나 SpEL 사용이 다른 컴포넌트 안에 내장된 경우 Spring 속성을 사용하여 컴파일러를 켤 수 있습니다. 이 섹션에서는 이 두 가지 옵션에 대해 설명합니다.

컴파일러는 세 가지 모드 중 하나에서 작동할 수 있으며, 이는org.springframework.expression.spel.SpelCompilerMode 열거형에 캡처되어 있습니다. 모드는 다음과 같습니다.

  • OFF (기본값): 컴파일러가 꺼져 있습니다.
  • 즉시: 즉시 모드에서는 표현식이 가능한 한 빨리 컴파일됩니다. 이는 일반적으로 첫 번째 해석된 평가 이후입니다. 컴파일된 표현식이 실패하는 경우(일반적으로 앞서 설명한 대로 유형 변경으로 인해) 표현식 평가의 호출자는 예외를 받습니다.
  • 혼합: 혼합 모드에서는 표현식이 시간이 지남에 따라 해석 모드와 컴파일 모드 간에 자동으로 전환됩니다. 해석된 형태로 몇 번 실행되면 컴파일된 형태로 전환되고, 컴파일된 형태에 문제가 발생하면(앞서 설명한 대로 유형이 변경되는 등) 표현식은 자동으로 다시 해석된 형태로 전환됩니다. 나중에 다른 컴파일된 형식을 생성하여 전환할 수도 있습니다. 기본적으로 사용자가 IMMEDIATE 모드에서 발생하는 예외는 내부적으로 처리됩니다.

MIXED 모드에서는 부작용이 있는 표현식에 문제가 발생할 수 있기 때문에IMMEDIATE 모드가 존재합니다. 컴파일된 표현식이 부분적으로 성공한 후 폭발하는 경우 이미 시스템 상태에 영향을 미치는 작업을 수행했을 수 있습니다. 이 경우 표현식의 일부가 두 번 실행될 수 있으므로 호출자는 해석 모드에서 자동으로 다시 실행되는 것을 원하지 않을 수 있습니다.

모드를 선택한 후 SpelParserConfiguration을 사용하여 구문 분석기를 구성합니다. 다음 예제는 그 방법을 보여줍니다.

SpelParserConfiguration config = new SpelParserConfiguration(SpelCompilerMode.IMMEDIATE,
		this.getClass().getClassLoader());

SpelExpressionParser parser = new SpelExpressionParser(config);

Expression expr = parser.parseExpression("payload");

MyMessage message = new MyMessage();

Object payload = expr.getValue(message);

컴파일러 모드를 지정할 때 ClassLoader를 지정할 수도 있습니다( null을전달해도 됨). 컴파일된 표현식은 제공된 모든 클래스에서 생성된 하위 클래스 로더에 정의됩니다. 클래스 로더가 지정되면 표현식 평가 프로세스에 관련된 모든 유형을 볼 수 있는지 확인하는 것이 중요합니다.클래스 로더를 지정하지 않으면 기본 클래스 로더 (일반적으로 표현식 평가 중에 실행 중인 스레드의 컨텍스트 클래스 로더 )가 사용됩니다.

컴파일러를 구성하는 두 번째 방법은 SpEL이 다른 컴포넌트 안에 내장되어 있어 구성 객체를 통해 구성할 수 없는 경우에 사용합니다. 이러한 경우 JVM 시스템 프로퍼티를 통해(또는SpringProperties 메커니즘을 통해) spring.expression.compiler.mode프로퍼티를SpelCompilerMode 열거형 값 중 하나(off, immediate 또는 mixed)로 설정할 수 있습니다.

컴파일러 제한

Spring은 모든 종류의 표현식 컴파일을 지원하지 않습니다. 주로 성능이 중요한 컨텍스트에서 사용될 가능성이 높은 일반적인 표현식에 중점을 둡니다. 다음과 같은 종류의 표현식은 컴파일할 수 없습니다.

  • 할당을 포함하는 표현식
  • 변환 서비스에 의존하는 표현식
  • 사용자 정의 리졸버 또는 접근자를 사용하는 표현식
  • 오버로드된 연산자를 사용하는 표현식
  • 배열 구성 구문을 사용하는 표현식
  • 선택 또는 투영을 사용하는 표현식

향후 추가 종류의 표현식 컴파일이 지원될 수 있습니다.

 

Expressions in Bean Definitions

XML 기반 또는 어노테이션 기반 구성 메타데이터와 함께 SpEL 표현식을 사용하여 BeanDefinition 인스턴스를 정의할 수 있습니다. 두 경우 모두 표현식을 정의하는 구문은 #{ <표현식 문자열> } 형식입니다.

XML Configuration

다음 예제에서 볼 수 있듯이 표현식을 사용하여 속성 또는 생성자 인수 값을 설정할 수 있습니다:

<bean id="numberGuess" class="org.spring.samples.NumberGuess">
	<property name="randomNumber" value="#{ T(java.lang.Math).random() * 100.0 }"/>

	<!-- other properties -->
</bean>

애플리케이션 컨텍스트의 모든 빈은 공통 빈 이름을 가진 미리 정의된 변수로 사용할 수 있습니다. 여기에는 런타임 환경에 대한 액세스를 위한 환경 (org.springframework.core.env.Environment 유형)과 같은 표준 컨텍스트 빈과 시스템 프로퍼티 및시스템 환경 ( Map<String, Object> 유형)이 포함됩니다.

다음 예제에서는 시스템프로퍼티 빈을 SpEL 변수로 액세스하는 방법을 보여 줍니다:

<bean id="taxCalculator" class="org.spring.samples.TaxCalculator">
	<property name="defaultLocale" value="#{ systemProperties['user.region'] }"/>

	<!-- other properties -->
</bean>

여기서 미리 정의된 변수 앞에 # 기호를 붙일 필요는 없습니다.

다음 예제에서와 같이 이름으로 다른 빈 속성을 참조할 수도 있습니다:

<bean id="numberGuess" class="org.spring.samples.NumberGuess">
	<property name="randomNumber" value="#{ T(java.lang.Math).random() * 100.0 }"/>

	<!-- other properties -->
</bean>

<bean id="shapeGuess" class="org.spring.samples.ShapeGuess">
	<property name="initialShapeSeed" value="#{ numberGuess.randomNumber }"/>

	<!-- other properties -->
</bean>

Annotation Configuration

기본값을 지정하려면 필드, 메서드, 메서드 또는 생성자 매개변수에 @Value 어노테이션을 배치하면 됩니다.

다음 예제는 필드의 기본값을 설정합니다:

public class FieldValueTestBean {

	@Value("#{ systemProperties['user.region'] }")
	private String defaultLocale;

	public void setDefaultLocale(String defaultLocale) {
		this.defaultLocale = defaultLocale;
	}

	public String getDefaultLocale() {
		return this.defaultLocale;
	}
}

다음 예제는 이와 동일하지만 속성 설정자 메서드에 대한 예제입니다:

public class PropertyValueTestBean {

	private String defaultLocale;

	@Value("#{ systemProperties['user.region'] }")
	public void setDefaultLocale(String defaultLocale) {
		this.defaultLocale = defaultLocale;
	}

	public String getDefaultLocale() {
		return this.defaultLocale;
	}
}

다음 예제에서 볼 수 있듯이 자동 연결 메서드와 생성자에도 @Value 어노테이션을 사용할 수 있습니다:

public class SimpleMovieLister {

	private MovieFinder movieFinder;
	private String defaultLocale;

	@Autowired
	public void configure(MovieFinder movieFinder,
			@Value("#{ systemProperties['user.region'] }") String defaultLocale) {
		this.movieFinder = movieFinder;
		this.defaultLocale = defaultLocale;
	}

	// ...
}
public class MovieRecommender {

	private String defaultLocale;

	private CustomerPreferenceDao customerPreferenceDao;

	public MovieRecommender(CustomerPreferenceDao customerPreferenceDao,
			@Value("#{systemProperties['user.country']}") String defaultLocale) {
		this.customerPreferenceDao = customerPreferenceDao;
		this.defaultLocale = defaultLocale;
	}

	// ...
}

 

언어 참조 (하위 섹션은 번역 생략)

이 섹션에서는 Spring 표현식 언어의 작동 방식을 설명합니다.

 

Classes Used in the Examples

이 섹션에는 이 장의 예제에서 사용된 클래스가 나열되어 있습니다.

Inventor

package org.spring.samples.spel.inventor;

import java.util.Date;
import java.util.GregorianCalendar;

public class Inventor {

	private String name;
	private String nationality;
	private String[] inventions;
	private Date birthdate;
	private PlaceOfBirth placeOfBirth;

	public Inventor(String name, String nationality) {
		GregorianCalendar c= new GregorianCalendar();
		this.name = name;
		this.nationality = nationality;
		this.birthdate = c.getTime();
	}

	public Inventor(String name, Date birthdate, String nationality) {
		this.name = name;
		this.nationality = nationality;
		this.birthdate = birthdate;
	}

	public Inventor() {
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public String getNationality() {
		return nationality;
	}

	public void setNationality(String nationality) {
		this.nationality = nationality;
	}

	public Date getBirthdate() {
		return birthdate;
	}

	public void setBirthdate(Date birthdate) {
		this.birthdate = birthdate;
	}

	public PlaceOfBirth getPlaceOfBirth() {
		return placeOfBirth;
	}

	public void setPlaceOfBirth(PlaceOfBirth placeOfBirth) {
		this.placeOfBirth = placeOfBirth;
	}

	public void setInventions(String[] inventions) {
		this.inventions = inventions;
	}

	public String[] getInventions() {
		return inventions;
	}
}

PlaceOfBirth

package org.spring.samples.spel.inventor;

public class PlaceOfBirth {

	private String city;
	private String country;

	public PlaceOfBirth(String city) {
		this.city=city;
	}

	public PlaceOfBirth(String city, String country) {
		this(city);
		this.country = country;
	}

	public String getCity() {
		return city;
	}

	public void setCity(String s) {
		this.city = s;
	}

	public String getCountry() {
		return country;
	}

	public void setCountry(String country) {
		this.country = country;
	}
}

Society

package org.spring.samples.spel.inventor;

import java.util.*;

public class Society {

	private String name;

	public static String Advisors = "advisors";
	public static String President = "president";

	private List<Inventor> members = new ArrayList<>();
	private Map officers = new HashMap();

	public List getMembers() {
		return members;
	}

	public Map getOfficers() {
		return officers;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public boolean isMember(String name) {
		for (Inventor inventor : members) {
			if (inventor.getName().equals(name)) {
				return true;
			}
		}
		return false;
	}
}


반응형
profile

while(1) work();

@유호건

❤️댓글은 언제나 힘이 됩니다❤️ 궁금한 점이나 잘못된 내용이 있다면 댓글로 남겨주세요.

검색 태그