유효성이 있는지 없는지에대한 중대한 질문은 비지니스 논리(business logic)에서 충분히 고려되어야 한다. 답변들 사이에는 찬반 양론이 있다 그리고 Spring은 그것들중의 어떤것도 배타적이지 않은 유효성 (그리고 data binding)을 위한 디자인을 제공한다. 유효성은 명확하게 웹계층과 연관이 없어야하고, 어떤 장소에 배치하기(localize) 쉬워야한다 그리고 어떤 유효성을 가능하게하는 사람이 플러그인 할 수 있게 해야한다. 위에서 말한것을 고려하면, Spring은 어플리케인션 모든 계층내에 기본적이고 사용할 수 있는것 사이의 Validator 인터페이스를 제안하고 있다(has come up with).
Data binding은 어플리케이션 도메인 모델(또는 당신이 사용자 입력 진행을 위해 사용하는 객체들 무엇이든지)에 다이나믹하게 묶인것을 허락된 사용자가 입력하기에 유용하다. Spring은 Data binding을 정확하게 하기위해 소위 DataBinder을 제공한다. Validator와 DataBinder는 유효성 패키지를 구성하고, 처음에 사용되었던것 안에 구성되어있다. 그러나 MVC framework안에 제안되어있지는 않다.
BeanWrapper는 Spring Framework 내의 기본적인 개념이고, 많은곳에서 사용되어진다. 그러나, BeanWrapper를 직접 사용할 필요는 아마 결코 없을 것이다. 이것은 참고 문서이기 때문에, 우리는 적절한 몇몇 설명을 생각해 본다. 이번 장(chapter)에서는 BeanWrapper를 설명한다. 만약 여러분이 이것을 모두 사용한다면, 아마 BeanWrapper와 강하게 관련이 있는 객체인 bind data를 연습해 볼 수 있을것이다.
스프링은 모든 장소위에 PropertyEditors를 사용한다. PropertyEditor의 개념은 JavaBeans 명세(specification)의 일부분이다. BeanWrapper와 DataBinder가 밀접하게 연관된 이후로, BeanWrapper일때, 또한 이번 장(chapter)내에 PropertyEditors 사용을 잘 설명한다.
DataBinder은 BeanWrapper 위에 만든다(builds).[2].
org.springframework.beans 패키지는 Sun에서 제공하는 JavaBeans 표준을 고수한다(adhere). JavaBean은 인수가 없는 디폴트 구성자로된 간단한 클래스이고, prop이란 이름의 속성(property)은 setter setProp(...) 과 getter getProp()을 가진 네이밍 규칙을 따른다. JavaBeans과 명세서에 관한 더 많은 정보를 위해서, Sun의 웹사이트(java.sun.com/products/javabeans)를 방문하기 바란다.
beans 패키지의 아주 중요한 한가지는 BeanWrapper 인터페이스이고 인터페이스에 대응하는 구현(BeanWrapperImpl)이다. JavaDoc의 주석과 같이 BeanWrapper는 기능적인 set과 get 속성값들(개별적인 하나하나 또는 대량)을 제공하고, 속성 서술자들(descriptors)을 얻고, 읽거나 쓸수있는지를 결정하는 속성들을 질의한다(query). 또한, BeanWrapper는 내포된 속성들을 위한 지원을 제공하고, 제한된 깊이의 하위-속성내의 속성을 설정 가능하게 해준다. 그 다음, BeanWrapper은 target 클래스안에 지원 코드의 필요 없이 PropertyChangeListeners와 VetoableChangeListeners 표준 JavaBeans를 더하는 능력을 지원한다. 마지막으로, BeanWrapper는 인덱스 속성들을 설정하기위한 지원을 제공한다. BeanWrapper은 보통 직접적으로 애플리케이션 코드에 사용되지 않는다. 하지만 DataBinder과 BeanFactory에는 사용된다.
BeanWrapper를 작업하는 방법은 부분적으로 이름에의해 지시되어진다: 설정속성들과 검색한 속성들과 같이 it wraps a bean은 bean안에서 활동이 수행된다. (it wraps a bean to perform actions on that bean, like setting and retrieving properties.)
Setting과 getting 속성들은 setPropertyValue(s) 과 getPropertyValue(s) 메소드를 사용한다. (Setting and getting properties is done using the setPropertyValue(s) and getPropertyValue(s) methods that both come with a couple of overloaded variants.) Spring JavaDoc안에 더 자세한 모든것이 설명되어있다. 중요하게 알아야할것은 한객체가 지시하는 속성에 맞는 연결된(a couple of) 규약이다. 연결된 예들:
Table 4.1. Examples of properties
Expression | Explanation |
---|---|
name | name과 대응하는 속성은 getName() 또는 isName() 그리고 setName()를 나타낸다. |
account.name | account 속성의 내포된 name과 대응되는 것은 속성은 예를드면 getAccount().setName() 또는 getAccount().getName() 메소드들을 나타낸다. |
account[2] | account의 인덱스(Indexed) 속성, 세가지요소를 나타낸다. 인덱스 속성은 array의 형태, list 또는 있는 그대로의 순서화된 collection의 형태로 나타낼수 있다. |
account[COMPANYNAME] | account Map 속성의 COMPANYNAME 키는 색인한 map entry의 값을 나타낸다. |
get과 set 속성들을 BeanWrapper로 작업한 몇몇 예제들은 아래에 있다.
주의 : 이부분은 직접적으로 BeanWrapper를 작업할 계획이 없으면 중요하지 않다. 만약 DataBinder와 BeanFactory 그리고 아래 박스이외의(out-of-the-box) 구현을 사용한다면 PropertyEditors section으로 넘어가라.
다음 두 클래스들을 주시하라 :
public class Company { private String name; private Employee managingDirector; public String getName() { return this.name; } public void setName(String name) { this.name = name; } public Employee getManagingDirector() { return this.managingDirector; } public void setManagingDirector(Employee managingDirector) { this.managingDirector = managingDirector; } }
public class Employee { private float salary; public float getSalary() { return salary; } public void setSalary(float salary) { this.salary = salary; } }
다음 코드 조각들은 검색하는 방법과 속성들을 사례를 들어 증명하는 조작에 대한 예들이 있다: Companies 과 Employees
Company c = new Company(); BeanWrapper bwComp = BeanWrapperImpl(c); // setting the company name... bwComp.setPropertyValue("name", "Some Company Inc."); // ... can also be done like this: PropertyValue v = new PropertyValue("name", "Some Company Inc."); bwComp.setPropertyValue(v); // ok, let's create the director and tie it to the company: Employee jim = new Employee(); BeanWrapper bwJim = BeanWrapperImpl(jim); bwJim.setPropertyValue("name", "Jim Stravinsky"); bwComp.setPropertyValue("managingDirector", jim); // retrieving the salary of the managingDirector through the company Float salary = (Float)bwComp.getPropertyValue("managingDirector.salary");
Spring은 PropertyEditors의 개념을 많이(heavily) 사용한다. 때때로 객체 자신보다 다른 방법으로 속성들을 알맞게 나타낼수 있을지도 모른다. 예를들어, 날짜는 사람이 읽을수 있는 방법으로 나타내야한다. 게다가 우리는 여전히 최초의 날짜를 거꾸로하여 사람이 읽을 수 있는 형태로 변환한다. (또는 더 나은것: Date objects의 뒤, 어떤 날짜를 사람이 읽을수 는 형태로 넣어 변환한다.) (or even better: convert any date entered in a human readable form, back to Date objects). 이 행위자는 java.beans.PropertyEditor 형태의 등록한 사용자 에디터들(registering custom editors)에의해 목적을 이룰수 있다. BeanWrapper내 또는 3장에서 언급한것 같이 특정한 Application Context 안에 등록한 사용자 에디터들은 속성들이 원하는 형태로 변환하는 방법이 주어진다. Sun사에서 제공하는 java.beans 패키지의 JavaDoc문서에있는 더많은 PropertyEditors 정보를 읽어라.
Spring에서 사용하되는 편집속성 예
beans내의 설정 속성들은 PropertyEditors를 사용된다. XML 파일안에 선언한 몇몇 bean 속성값과 같이 java.lang.String을 언급할때, Spring은 (상응하는 setter가 Class-parameter를 가지고 있다면 ) Class object의 인수를 결정하기위해 ClassEditor를 사용한다.
Spring MVC framework내의 HTTP request parameters 분석에는 CommandController의 모든 하위클래스로 수동으로 바인드 할 수 있는 PropertyEditors종류가 사용된다.
Spring은 생명주기(life)를 쉽게 만들기 위한 내장(built-in) PropertyEditors를 가진다. 각각은 아래에 목록화되어있고, org.springframework.beans.propertyeditors 패키지 안에 모두 위치해 있다. 대부분, (아래에 나타나 있는것과 같이) 모두 그런것은 아니고 BeanWrapperImpl 디폴트로 저장되어있다. 속성 에디터가 몇몇 형태로 구성할수 있고, 디폴트 형태를 오버라이드하여 자신의 형상으로 등록하는 과정을 할 수 있다. :
Table 4.2. 내장 PropertyEditors(Built-in PropertyEditors)
Class | 설명 |
---|---|
ByteArrayPropertyEditor | byte 배열을 위한 Editor. Strings은 간단하게 byte 표현과 상응하여 변환될 것이다. BeanWrapperImpl에 의해 디폴트로 등록된다. |
ClassEditor | Strings으로 표현된 클래스들을 실제 클래스와 다른 주위의 방법으로 분석하라. (Parses Strings representing classes to actual classes and the other way around.) 클래스를 찾을수 없을때, IllegalArgumentException을 던진다. BeanWrapperImpl에 의해 디폴트로 등록된다. |
CustomBooleanEditor | Boolean속성들을 위해 커스터마이즈할수 있는 속성 에디터(editor). BeanWrapperImpl에 의해 디폴트로 등록된다.그러나, custom 에디터에의해 등록된 custom 인스턴스에를 오버라이드할 수 있다. |
CustomCollectionEdit | Collection 형태의 목표가 주어졌을때 소스 Collection으로 전환하는, Collections을 위한 설정 editor. |
CustomDateEditor | custom DateFormat을 지원한, java.util.Date을 위한 커스터마이즈할 수 있는 설정 editor. 디폴트에의해 등록할 수 없다. 사용자가 적절한 포맷을 소유함으로써 등록되어져야 한다. |
CustomNumberEditor | Integer, Long, Float, Double과 같은 Number 서브클래스를 위한 커스터마이즈할 수 있는 설정 에디터. 그러나, 사용자(custom) 에디터로써 등록된 사용자(custom) 인스턴스를 오버라이드할 수 있다. |
FileEditor | Strings에서 File-객체들을 결정 가능.(Capable of resolving Strings to File-objects.) BeanWrapperImpl에 의해 디폴트로 등록된다. |
InputStreamEditor | 단방향 설정 에디터는 텍스트 문자열을 가질 수 있고, InputStream을 생성할 수 있다 (ResourceEditor와 Resource의 조정자를 통해서). 그래서 InputStream 속성들은 Strings에서 File-객체들을 결정하는데 직접적으로 setCapable을 쓸 수도 있다. 디폴트 사용은 InputStream을 끝맺지(close) 않는다는 것을 주의하라!. BeanWrapperImpl에 의해 디폴트로 등록된다. |
LocaleEditor | Strings에서 Locale-객체들을 결정 가능하고 반대로 Locale의 toString() 메소드도 같은 기능을 제공한다(String 포맷은 [language]_[country]_[variant]이다) . BeanWrapperImpl에 의해 디폴트로 등록된다. |
PropertiesEditor | Strings(Javadoc 안의 java.lang.Properties class에서 정의된 포맷되어 사용된 형태)을 Properties-객체들로 변환 가능하다. BeanWrapperImpl에 의해 디폴트로 등록된다. |
StringArrayPropertyEditor | String을 String-배열로 콤마-범위로 목록화하여 결정할 수 있고, 반대로도 가능하다. BeanWrapperImpl에 의해 디폴트로 등록된다. |
StringTrimmerEditor | Property 에디터는 Strings을 정리 정돈한다. 선택적으로 널(null) 값으로 되어있는 변형된 비어있는 문자열로 인정한다. 디폴트에의해 등록되어지지 않는다. 사용자는 필요할때에 등록해야한다. |
URLEditor | URL의 String 표현을 실제 URL-객체로 결정할 수 있다. BeanWrapperImpl에 의해 디폴트로 등록된다. |
Spring은 설정 에디터들이 필요할지도 모르는 것을 위하여 경로 찾기를 정하는 java.beans.PropertyEditorManager를 사용한다. 경로 찾기는 또한 글꼴, 색상, 모든 원시 형태들의 PropertyEditors를 포함하고 있는 sun.bean.editors를 나타낸다. 만약 다루는 클개스가 같은 패키지 안에 있고, 클래스가 같은 이름을 가지고 있고, 'Editor'가 추가되어있다면, 또한 표준 JavaBeans 기초구조는 (등록하는 절차 없이) 자동적으로 PropertyEditors를 발견한다는 것을 주의하라.
전체 섹션에서 그렇게 가치가 있지는 않지만, 그밖에 여러분이 흥미로와 했을지도 모를 연관된 기능들은 전 섹션에서 본 기능들이다.
가독성과 쓸수있는지 특성 결정: isReadable()과 isWritable() 메소드를 사용함은 속성이 가독성이 있는지 쓸수있는지를 결정할 수 있다.
검색하는 PropertyDescriptors: getPropertyDescriptor(String)과 getPropertyDescriptors()를 사용함은 java.beans.PropertyDescriptor형태의 객체들을 검색할 수 있고, 때때로 편리할지도 모른다.