AddEmptyString


우선순위 : 3

The conversion of literals to strings by concatenating them with empty strings is inefficient. It is much better to use one of the type-specific toString() methods instead.

 

문자열로 형변환을 할 때 빈 문자열로 + 연산을 하는 것은 비효율적이다.
이럴 경우에는 각 타입별로 구현된 toString() 메소드를 이용하는 것이
더 낫다.

 

샘플 코드



AvoidArrayLoops


우선순위 : 3

Instead of manually copying data between two arrays, use the efficient System.arraycopy method instead.

 

두 배열간에 복사를 할 때는 루프를 통해 수동적으로 하지 말고
System.arraycopy를 이용하는 것이 더 효율적이다.

 

샘플 코드

 

부연설명

 

System.arraycopy 사용법
System.arraycopy는 다음과 같은 5개의 인자를 받는다.

 

Object src : 복사할 원본 소스 배열
int srcPos : 소스에서 복사를 시작할 index
Object dest : 소스를 복사할 대상 배열
int destPos : 대상 배열에서 쓰기 시작할 index
int length : 원본에서 몇개의 요소를 읽어올지에 대한 길이

 

예제

결과

destStrArr1 : null
destStrArr1 : null
destStrArr1 : 요소1
destStrArr1 : 요소2
destStrArr1 : null

=======================================

destStrArr2 : 요소1
destStrArr2 : 요소2
destStrArr2 : 요소3
destStrArr2 : 요소4
destStrArr2 : 요소5




RedundantFieldInitializer


우선순위 : 3

Java will initialize fields with known default values so any explicit initialization of those same defaults is redundant and results in a larger class file (approximately three additional bytecode instructions per field).

 

자바의 멤버 변수들은 잘 알려진 값으로 자동 초기화 되므로 명시적으로 이러한
기본값으로 초기화 할 필요가 없으며 초기화할 경우 오히려 용량만 많이 차지하게 된다.

 

샘플 코드

 

부연 설명

아래 추가 샘플코드에 보면 FieldTest의 멤버변수들인 b,s,i,l,d,f,o 등은
아무런 초기화를 하지 않았지만 실제로 프린트를 해보면 기본값일이 출력되는 것을
알 수 있다.

 

FieldTest.java

PMDTestMain.java

 

결과

b = false
s = null
i = 0
l = 0
d = 0.0
f = 0.0
o = null


저작자 표시
신고



변수명 맞추기...


잘 만들어지고 있던 사이트에 마지막 기능을 추가하는 중...
갑자기 등록과 수정(POST,PUT) 과정에서 400 Bad Request 오류가
발생을 한다.


다른 메뉴에서는 잘 되는 것으로 보아 설정의 문제는 아니고...
새로 구현된 기능에 국한된 문제인 듯싶은데...


반나절 이상을 날리면서 오늘 아침 겨우 찾아낸 문제의 원인은...
서버측 domain 클래스의 변수명과 등록/수정 시 넘기는
JSON 문자열의 변수명이 일치하지 않았던 것...ㅠ.ㅠ


서버쪽에서 변수명에 오타가 하나 있어 수정을 했는데
클라이언트쪽에서 수정을 안한 것이다.


참으로 소박한 실수였다...ㅠ.ㅠ

저작자 표시
신고




AvoidInstantiatingObjectsInLoops


우선순위 : 3

New objects created within loops should be checked to see if they can created outside them and reused.

 


Loop 안에서 객체의 인스턴스를 생성할 때는 Loop 밖에서 생성한 후 재사용 가능한지
확인하라


 

샘플코드

 


부연설명

 

잘 아다시피 instance를 생성한다는 것은 메모리를 사용한다는 의미다.
루프 안에서 객체의 인스턴스를 생성한다는 것은 곳 루프가 도는 만큼 메모리를
소비하게 된다는 이야기다. 하지만 이 룰에 강제성을 두지 않은 이유는 참조타입의
변수 각각에 서로 다른 값을 가지게 해야 할 경우 루프 밖에서 인스턴스를 생성한 후
루프 안에서 값을 할당하게 되면 모든 인스턴스가 동일한 값을 가지게 되어
의도한 대로 작동하지 않게 되기 때문이다. 따라서 이 룰은 잘 판단을 하여 사용해야 한다.




SimplifyStartsWith


우선순위 : 3

Since it passes in a literal of length 1, calls to (string).startsWith can be rewritten using (string).charAt(0) at the expense of some readability.

 


문자열의 길이가 1이라면 startsWith 메소드를 사용하는 것보다 charAt(0)을 사용하는 것이
더 효율적이다.


 

샘플 코드





UseStringBufferForStringAppends


우선순위 : 3

The use of the ‘+=’ operator for appending strings causes the JVM to create and use an internal StringBuffer. If a non-trivial number of these concatenations are being used then the explicit use of a StringBuilder or threadsafe StringBuffer is recommended to avoid this.

 


문자열을 합치기 위한 ‘+=‘ 연산은 JVM에서 내부적으로 StringBuffer를 생성하여
사용한다. 따라서 통상적인 범위를 넘어서는 문자열 연결이라면 명시적으로
StringBuilder나 혹은 thread에 안정적인 StringBuffer(threadsafe한 대신
조금 느림)를 사용하도록 권고한다.


 

샘플코드

 


부연설명
PMD에서 뿐만 아니라 일상적인 코딩에서도 논란이 많은 룰입니다.
이미 내부적으로 StringBuffer를 사용하므로 그냥 += 연산자를 사용해도 되지
않느냐는 말들도 참 많이 합니다. 룰 설명에도 ‘통상적인 범위를 넘어서는’이라는
전제를 달고 있고…
현재까지의 가장 합리적인 절충안은 적어도 loop안에서는 += 사용을 지양하는 정도가
되겠네요.
오히려 += 연산자를 쓰느냐 마느냐보다는 StringBuffer와 StringBuilder를 선별해서
사용하는데 주의를 기울여야 할 것 같습니다.




UseArraysAsList


우선순위 : 3

The java.util.Arrays class has a “asList” method that should be used when you want to create a new List from an array of objects. It is faster than executing a loop to copy all the elements of the array one by one.

 

배열(Arrays)을 List로 변환하는 경우 Array 클래스에 있는 asList 메소드를 이용하는 것이
루프문을 통해 하나하나 복사하는 것보다 더 빠르므로 asList 메소드를 사용하는 것이 좋다.

 

샘플 코드


저작자 표시
신고



PositionLiteralsFirstInComparisons


우선순위 : 3

 

Position literals first in comparisons, if the second argument is null then NullPointerExceptions can be avoided, they will just return false.

 

equals()를 통한 비교를 할 때는 항상 상수 값을 앞에 두어야 한다.
만일 두번째 인자가 null인 경우에는 NullPointerException이 발생하지 않으며
단순히 false를 리턴하게 된다.

 

하지만 상수가 아닌 참조타입의 변수가 앞에 오게 되면 이 변수가 null인 경우
NullPointerException이 발생하게 된다.

 

샘플 코드




UnnecessaryLocalBeforeReturn


우선순위 : 3

Avoid the creation of unnecessary local variables

 

불필요한 지역변수를 만들지 말라.

 

모든 변수는 메모리를 사용하는 만큼 가급적이면 꼭 필요한 변수만
필요할 때 만들어서 사용하는 것이 좋을 것이다. 이 것이 힘들다면
절대 필요하지 않을 것 같은 변수는 만들지 않는 것이 좋을 것이다.

 

샘플 코드




AvoidConstantsInterface


우선순위 : 3

An interface should be used only to characterize the external behaviour of an implementing class: using an interface as a container of constants is a poor usage pattern and not recommended.

 

인터페이스란 클래스가 외부와 어떤 행위를 하도록 하는 내용으로 구현되어야만 한다.
단지 상수를 저장해놓는 컨테이너로만 사용되는 인터페이스는 권장되지 않는다.

 

샘플 코드 (나쁜 예)





UseCollectionIsEmpty


우선순위 : 3

The isEmpty() method on java.util.Collection is provided to determine if a collection has any elements. Comparing the value of size() to 0 does not convey intent as well as the isEmpty() method.

 


컬렉션 객체에 엘리먼트들이 없다는 것을 확인하기 위해서는 size() == 0 보다는
isEmpty() 사용이 권장된다. size()를 통한 비교는 isEmpty()에 비해 그 의도가
명확하게 전달되지 않는다.

 

샘플코드

 

부연설명

일반적으로 isEmpty() 메소드와 size() 메소드의 성능상의 차이는 없는 것으로 보아도
좋습니다. 다만 메소드 명에서 드러나는 ‘의도’가 isEmpty쪽이 좀 더 분명하다는
장점이 있습니다. 참고로 ArrayList에 구현된 isEmpty() 메서드와 size() 메서드의
내용은 다음과 같습니다.





ReturnEmptyArrayRatherThanNull


우선순위 : 1

For any method that returns an array, it is a better to return an empty array rather than a null reference. This removes the need for null checking all results and avoids inadvertent NullPointerExceptions.

 


배열을 리턴하는 메소드에서 배열에 엘리먼트가 없더라도
null 보다는 빈 배열을 리턴하는 것이 좋다.
이렇게 하는 것은 불필요한 null 체크를 피할 수 있을 뿐만 아니라
의도하지 않은 NullPointerException이 발생하지 않도록 할 수도 있다.

 

샘플 코드


저작자 표시
신고



FinalFieldCouldBeStatic


우선순위 : 3

 

컴파일 타임에 상수가 할당되는 final 필드는 자동으로 static으로 변환된다.
따라서 이러한 필드들은 runtime시의 부하를 줄여주기 위해 static을 명시적으로
지정해주는 것이 좋다.

 

샘플 코드



OptimizableToArrayCall


우선순위 : 3

Calls to a collection’s toArray() method should specify target arrays sized to match the size of the collection. Initial arrays that are too small are discarded in favour of new ones that have to be created that are the proper size.

컬렉션 객체의 toArray() 메소드를 호출할 때에는 대상 배열 크기를 명확하게 컬렉션
객체의 크기와 동일하게 맞춰야 한다.

너무 작은 크기의 초기 배열은 알맞은 크기의 배열이 생성되도록 하기 위해
그냥 버려지기 때문에 비효율적이다.

 

샘플 코드



ConfusingTernary


우선순위 : 3

Avoid negation within an “if” expression with an “else” clause. For example, rephrase:

if (x != y) diff(); else same(); as: if (x == y) same(); else diff();

Most “if (x != y)” cases without an “else” are often return cases, so consistent use of this rule makes the code easier to read. Also, this resolves trivial ordering problems, such as “does the error case go first?” or “does the common case go first?”.

 

비교구문에 부정연산자(!)를 사용하는 것은 피하는 것이 좋다.
어차피 if (x != y) diff(); else same();와 if (x == y) same(); else diff();는
동일하며 대체로 “if (x != y)”로 표현하는 경우에는 else문 없이 if문 안에서 바로
리턴하는 경우가 많기 때문에 이러한 룰을 일관성 있게 지켜서 코딩하는 것이
가독성을 높이는 방법 중 하나다.

 

그리고 이러한 것들이 사소하게는 문제 처리의 순서
즉,에러를 먼저 처리할 것인지, 정상 코드를 먼저 처리할 것인지에 대한 부분도
해결해 줄 수 있다.

 

샘플 코드



SimpleDateFormatNeedsLocale


우선순위 : 3

Be sure to specify a Locale when creating SimpleDateFormat instances to ensure that locale-appropriate formatting is used.

 

적절한 지역화 포맷이 필요한 경우에는 SimpleDateFormat의 인스턴스를 생성할 때
확실하게 locale을 지정하라.

 

샘플 코드



SimplifyConditional


우선순위 : 3

No need to check for null before an instanceof; the instanceof keyword returns false when given a null argument.

 

조건절에 instanceof 연산자를 사용할 경우에는 그 앞에 null 체크를 할 필요가 없다.
instanceof 연산자는 비교 대상이 null인 경우 false를 리턴한다.

 

샘플 코드

 

부연 설명

오라클의 자바 공식 문서에 보면 instanceof 연산자는 연산 대상으로 참조 타입이나
null 타입을 사용할 수 있다고 합니다. 그렇지 않은 경우 컴파일시에 오류가 발생을
합니다.

 

따라서 연산자로 null이 사용되는 경우에는 문제가 없으나 int, String, boolean 같은
기본형을 대상으로 하는 경우에는 컴파일 에러가 발생합니다.


저작자 표시
신고



ConstructorCallsOverridableMethod

우선순위 : 1

영어 실력이 그지같아서  번역이 힘드네요…원문 적고 설명은 샘플 밑에 부연 설명으로 대신하겠습니다.

마지막 줄만 설명하자면 일반적인 제어의 흐름을 따르는 메소드 호출을 하라는 것인데 예를들어

생성자인 Foo()에서 public 메소드인 buz()를 호출하는 private 메소드 bar()를 호출하는 것과 같이 비비 꼬아놓으면

문제의 소지가 있다는 말입니다.

 

원문

Calling overridable methods during construction poses a risk of invoking methods on an incompletely constructed object and can be difficult to debug. It may leave the sub-class unable to construct its superclass or forced to replicate the construction process completely within itself, losing the ability to call super(). If the default constructor contains a call to an overridable method, the subclass may be completely uninstantiable. Note that this includes method calls throughout the control flow graph – i.e., if a constructor Foo() calls a private method bar() that calls a public method buz(), this denotes a problem.

 

샘플 코드

SeniorClass

JuniorClass

 

 

부연 설명

위 샘플 코드를 직접 돌려보면 결과가 다음과 같이 나옵니다.

SeniorClass.constructor
Exception in thread “main” JuniorClass.toString
java.lang.NullPointerException
at JuniorClass.toString(JuniorClass.java:12)
at SeniorClass.<init>(SeniorClass.java:5)
at JuniorClass.<init>(JuniorClass.java:4)
at PMDTestMain.main(PMDTestMain.java:10)

스택트레이스를 따라가보면 JuniorClass의 생성자 > SeniorClass의 생성자 > JuniorClass의 toString 순으로

호출 되고 있습니다. extends SeniorClass로 인해 이미 SeniorClass의 toString은 JuniorClass의 toString으로

바뀐 상태입니다. 결국 super()를 호출한 시점에서 벌써 JuniorClass의 toString이 호출되고 있으나

이 시점에는 아직 name에 값이 할당되기 전이기 때문에 위와같이 NullPointerException이 발생하게 됩니다.


LocalVariableCouldBeFinal

우선순위 : 3

지역변수가 최초 값 할당 이후 값이 변경하지 않는다는 것을 보장하기 위해서

final 변수로 지정할 수 있다.

 

샘플 코드

 

 

부연 설명

만일 메소드 내의 특정 지역변수가 메소드의 처리 과정 내에서 그 값이 변하면 안되는 경우에는

실수에 의한 값 변경을 막기 위해서 final로 사용하는 것도 좋은 방법이라는 의미입니다.

아시다시피 final 변수에 값을 할당하게 되면 컴파일 시에 에러가 발생하기 때문에 쉽게 문제를 발견할 수 있게 됩니다.


AvoidReassigningParameters

우선순위 : 2

메소드에 전달된 파라미터를 직접 재할당하는 것은 피해야 한다.

임시 지역변수를 이용하여 값을 변경하는 것이 좋다.

 

샘플 코드

 

부연 설명

JAVA에서는 매개변수를 전달할 경우 primitive 타입은 변수 값의 복사본을 전달하지만 Object 타입을 전달할 경우

복사본이 아닌 참조값(변수가 저장된 메모리의 주소)를 넘기게 됩니다.

따라서 매개변수에 직접 새로운 값을 할당 할 경우 사실상 primitive 타입을 받은 경우에는 심각한 문제가 발생하지는

않습니다. 다만 코드가 길어질 경우 ‘분명히 X값을 넘겼는데 왜 Y’값으로 바뀌었지?’ 하는 혼란이 생길 수 있습니다.

하지만 Object 타입의 경우는 문제가 심각합니다. 전달받은 쪽에서 값을 변경하면 전달해준 쪽의 값도 같이 바뀌기 때문에…

따라서 특별한 목적이 있지 않는 한 전달받은 매개변수를 직접 수정하는 일은 없어야 합니다.

 

연습

결과

paramTest(할당 전) : strList.size = 4

paramTest(할당 전) : strItem = TEST1

paramTest(할당 전) : strItem = TEST2

paramTest(할당 전) : strItem = TEST3

paramTest(할당 전) : strItem = LOCALTEST4

paramTest(할당 후) : strList.size = 3

paramTest(할당 후) : strItem = LOCALTEST1

paramTest(할당 후) : strItem = LOCALTEST2

paramTest(할당 후) : strItem = LOCALTEST3

paramTest(할당 전) : str = STR_TEST1

paramTest(할당 후) : str = LOCAL_STR_TEST1

main : strList.size = 4

main : strItem = TEST1

main : strItem = TEST2

main : strItem = TEST3

main : strItem = LOCALTEST4

main : str = STR_TEST1



SimplifyBooleanReturns

우선순위 : 3

boolean 값을 리턴하게 될 때는 불필요한 분기문(if-else)을 사용하지 말아라.

대신에 조건을 테스트하는 문장 바로 리턴해도 된다.

샘플 코드

 

부연설명

추후 따로 설명을 하겠지만 if문이 늘어나면 Cyclomatic Complexity라고 하여 복잡성 지표가 올라가게 됩니다.

이는 코드의 가독성을 떨어뜨리고 이해를 어렵게 하는 원인이 되어 품질 관리에서는 특정 점수 이하로 유지하도록

하고 있습니다. (간단하게 복잡도 = 분기문 갯수 + 1이라고 생각하시면 됩니다.)

이러한 이유로 if문은 가능한한 사용하지 않는쪽으로 코딩을 하시는 것이 좋습니다.

저작자 표시
신고



NullAssignment

우선순위 : 3

코드 중간에서 변수에 null을 할당하는 것은 좋지 않은 형태이다.

이런 형태의 할당은 종종 개발자들이 프로그램의 흐름을 이해하지 못하고 코딩을 하고 있다는 표시가 될 수 있다.

주의 : 이런 형태의 경우가 드물게는 garbage collectoin에 도움이 되는 경우도 있다. (물론 잘 이해하고 사용했을

경우) 이렇게 의도하고 사용한 경우에는 이 룰을 무시해도 좋다.

 

샘플코드

 

부연 설명

이 경우 중요한 부부은 주석으로 표시된 ‘매우 크고 복잡한 코드’에 있다.

중간에 특정 변수를 null로 처리하는 경우 이를 제대로 인지하지 못하게 되면 뒤의 코드에서 null로 할당된

변수를 새로운 인스턴스로 할당하지 않고 바로 사용하게 될 소지가 있으며 이럴 경우 NullPointerException이

발생하게 될 것이다.

믈론 한 메소드 안에서 그렇게 길고 복잡한 코드를 사용하는 것 자체가 문제라면 문제지만…


OnlyOneReturn

우선순위 : 3

메소드에는 종료 포인트가 반드시 하나만 있어야 하며 이 종료 포인트는 반드시 메소드의 가장 마지막에

있어야 한다.

 

샘플코드 (나쁜 예)

 

부연 설명

이는 원칙적이고 일반적인 룰을 설명한 것이다.

흔히들 메소드 내에 if, if/else, while, for, try/catch등 각종 코드 블록이 만들어지고 각각의 블록에서

상황에 맞게 return문을 사용하는 경우가 많다. 상황에 따라 이렇게 할 수밖에 없는 경우도 있지만

이는 곧 코드의 복잡도(Cyclomatic Complexity)가 올라갔다는 반증이기도 하다.

가독성을 높이고 코드의 흐름을 원활하게 하기 위해서는 가능한한 return문은 하나만, 메소드의 가장

마지막에 위치할 수 있도록 하자.


AvoidLiteralsInIfCondition

우선순위 : 3

조건문의 조건식에 하드코딩 된 상수를 사용하지 말아라.

의미를 설명할 수 있는 이름을 가진 static 변수나 private 멤버 변수로 사용하는 것이 더 좋은 방법이다.

 

샘플코드

 

부연설명

위의 샘플코드에 ‘magic number’라는 표현이 나오는데 이 것은 Refactoring에서도 자주 언급되는 내용으로

마치 마술처럼 어떻게도 해석이 될 수 있다는 것을 빗댄 표현이다.

즉, 상수를 하드코딩해 놓았을 때 그 숫자 자체만으로는 어떤 의미인지 이해가 불가능하다.

따라서 이러한 숫자들은 static이나 private 멤버변수로 만들어 의미가 있는 이름으로 사용하도록

권장하고 있다.


UseObjectForClearerAPI

우선순위 : 3

public 메소드를 만들 때는 API 사용 조건에 대해 생각해야만 한다.

메소드를 public으로 만들었다는 것은 다른 클래스들에서 이 메소드를 사용하게 하는 것이고 따라서

보다 포괄적이고 개선된 API를 제공하고자 하는 것이다.

 

이런 경우 너무 많은 정보를 단순 나열 형태의 String으로 전달하게 된다면 이 파라미터들을 하나의 Object로

묶어 이 Object를 인자로 전달하는 것이 좋다. 일단 코딩이 길어지고 복잡해지는 것이나 파라미터의 갯수가

많음으로 해서 어떤 인자가 어떤 위치에 있어야 하는지에 대한 혼동을 줄일 수 있을 뿐더러 만일 전달해야 하는

파라미터의 수나 종류가 변경될 경우 이 Object만 수정하면 되기 때문이다.

 

샘플코드

 

저작자 표시
신고



AvoidBranchingStatementAsLastInLoop

우선순위 : 2

루프의 가장 마지막 위치에서 분기문을 사용하는 경우 버그가 발생할 가능성이 높다.

사용한 방법이 버그가 아닌지 확인하거나 다른 접근 방법을 사용해야 한다.

 

샘플 코드

 

부연설명

Loop문의 내의 continue문이나 break문은 문장의 흐름을 제어하는 역할로 가독성의 측면에서 본다면 문장의 정상적인

흐름을 방해하는 부분도 있습니다. 이러한 요소가 자주 사용된다는 것은 그만큼 문장의 흐름을 이해하기 힘들게 만들고

또 그러인해 버그가 발생할 가능성이 높아질 것입니다.

가급정 문장 흐름을 제어하는 문장은 적게 사용하는 것이 좋겠습니다.




SimplifiedTernary

우선순위 : 3

조건문?boolean 상수:foo 또는 조건문?foo:boolean 상수 형태의 3항 연산자를 사용이 필요하다면

이러한 문장은 각각 다음과 같이 간단하게 표현할 수 있다.

boolean 상수가 처음 결과이면서 true인 경우     : condition || foo

boolean 상수가 두 번째 결과이면서 true인 경우  : !condition || foo

boolean 상수가 처음 결과이면서 false인 경우    : !condition && foo

boolean 상수가 두 번째 결과이면서 false인 경우 : condition && foo

 

샘플 코드

 

3항 연산자는 대체로 가독성을 떨어뜨리므로 가능한한 단순한 표현으로 대체하라는 의미입니다.




~MustUseBraces

우선순위 : 3

 

이 룰셋에 해당하는 룰은 총 4가지가 있습니다.

전체적인 내용은 코드의 가독성을 위해 if, if/else, while, for문에 반드시 braces({})를 사용하라는 것입니다.

전체 내용 그대로 옮깁니다~

 

IfStmtsMustUseBraces

샘플 코드

 

WhileLoopsMustUseBraces

샘플코드

 

IfElseStmtsMustUseBraces

샘플코드

 

ForLoopsMustUseBraces

샘플코드

 



UnnecessaryConstructor

우선순위 : 3

 

다음과 같은 경우에는 생성자가 필요없습니다.

하나의 생성자만 있으며, public이고 생성자의 내용이 없으며 전달받은 인자가 없는 경우

 

샘플코드

 

 

부연설명

위와 같은 경우에는 컴파일러가 자동으로 기본 생성자를 생성하므로 굳이 명시적으로 코딩을 할 필요가 없다.

다만 기본 생성자가 아닌 새성자를 추가하게 되면 컴파일러는 기본생성자를 자동으로 추가하지 않으며

필요에 따라 기본 생성자를 코딩해주어야 한다.


저작자 표시
신고

지난 번 잠시 언급한 적이 있지만 현재 Spring 3.1.1 + MyBatis + jQuery + Bootstrap을 이용하여

업무에 사용할 작은 사이트를 만들고 있다.


기업체의 내부망에서 작업하는 중이라 소스를 공개하지 못하는 것이 못내 아쉽다.


사실 Spring을 다시 만져보는 것이 거의 7년만이라 약간의 낯설음은 있지만 그 낯설음을 상쇄할만한

변화가 있었기에 어렵지 않게 다시 시작해 볼 수 있었다.


그래도 어디 세상 일이 밥 달라면 밥 나오고 물 달라면 물 나오던가?

이래 저래 소소한 에러들을 자주 접하게 된다. 그리고 언제나 그렇듯 아무 것도 아닌 문제로

반나절을 그냥 날리기도 하고...


어차피 전문적인 내용이야 볼 수 있는 곳이 천지니 나는 내가 겪은 에러나 정리하련다.


1. Mapped Statemets collection already contains value for...

톰캣을 기동하는데 이런 메시지가 나오면서 디플로이가 제대로 안되었다.

얼핏 메시지 내용을 봐서는 어딘가 중복된 설정이 있거나 id명을 중복해서 썼거나 했을 것 같았는데...

나같은 경우 특정 Mapper의 Query문에 문제가 있었다.

갑자기 기억이...쿼리 자체의 오류였다기보다는 MyBatis 쿼리 설정 상의 문제였던가? 

하여간 이런 오류 만나면 Mapper에 있는 쿼리도 잘 살펴야 한다.


2. requestmappinghandlermapping did not find handler method for

요건 메시지 내용대로 request에 대한 mapping이 잘못되어 요청한 리소스를 찾을 수 없다는 뜻이다.

요런 것이 참 별것도 아니면서 시간 잡아먹는 하마다.

문제의 원인은 Controller에는 request parameter를 userId로 해놓고는 jQuery의 ajax 호출 시

파라미터 명을 userID라고 써서 발생한 문제였다.


3. Invalid bound Statement (not found): Mapper.function

요것도 메시지를 눈여겨 보면 답이 나온다.

문장과 Mapper의 함수가 연결이 안된다잖는가~

바로 Mapper.xml에 있는 쿼리 id와 Mapper.java에 있는 메소드 명이 달라서 발생한 문제다.


4. 건 에러는 아니지만 get방식으로 request할 때 한글 깨지는 문제 처리 방법이다.

클라이언트 측 : jQuery에서 한글로된 인자를 넘길 때 encodeURI(encodeURIComponent(value))로 넘긴다.

서버 측 : Controller에서 한글 인자를 받을 때 URLDecoder.decoded(value)로 처리해준다.


참...적어놓고 보니 초급자 수준의 실수가 날 울리네....ㅠ.ㅠ