스프링시큐리티의 GrantedAuthority 인터페이스를 enum 타입으로 구현했는데, 이 구현체에 toString() 을 선언하면서 의도와는 다르게 동작하는 문제가 발생했다.

public enum MemberAuthority implements OrderedGrantedAuthorityCodeableEnum {
    /**
     * Administrator
     */
    ADMINISTRATOR("administrator""code.memberAuthority.administrator"1),
    /**
     * Project Manager(project, project member, jobs of project management)
     */
    PROJECT_MANAGER("project-manager""code.memberAuthority.projectManager"2),
    /**
     * Operator( operator jobs of project)
     */
    OPERATOR("operator""code.memberAuthority.operator"3),
    /**
     * Inspector(monitoring)
     */
    INSPECTOR("inspector""code.memberAuthority.inspector"4);
 
    private String code;
    private String key;
    private int order;

이런 코드인데, toString() code, key, order 에 대한 내용을 출력하도록 만들면...MemberAuthority[code="project", key="code.memberAuthority.administrator", order=1]의 형태로 나오게 된다. 스프링시큐리티에서는 권한을 문자열로 받기에 ADMINISTRATOR 으로 나와야하는데... 전혀 다른 형태가 되어버리니 권한 체크가 제대로 되지 않을 수밖에...

○ 정리

  • enum 타입에 대해서 toString()을 적용할 때는 잠시만 고심해보자.



실행가능한 JAR(executable jar)을 생성하게 되면 다음과 같이 META-INF 폴더 밑에 MANIFEST.MF 파일이 생성된다.

├── Application.class
└── META-INF
    └── MANIFEST.MF

MANIFEST.MF 내용

  • Manifest specification
    Manifest-Version: 1.0
    Class-Path: .
    Main-Class: Application // 실행가능한jar의 엔트리포인트가 되는 클래스명
    

예제

  • java.util.jar.JarFile API를 이용해서 Jar 파일에 대한 정보를 읽어드릴 수 있다.
  • 다음과 같이 JDK6과 JDK7에서 가져올 수 있는 부분이 다른 것으로 보인다.

    ㅡ_-);; JDK6, JDK7, JDK8에서 다를 수 있는데 그걸 테스트하기가 좀… 귀찮…

JarFile jarFile = new JarFile(/** 식별하려고 하는 jar 파일*/);

private boolean hasMainClassManifest(JarFile jarFile) throws IOException {
    Double javaVersion = Double.parseDouble(System.getProperty("java.specification.version"));
    log.debug("Java version: {}", javaVersion);
    log.debug("Has Main-Class: {}", jarFile.getManifest().getEntries().containsKey("Main-Class"));
    log.debug("Has Main-Class: {}", jarFile.getManifest().getMainAttributes().getValue("Main-Class"));
    if(1.7 > javaVersion) {
        return jarFile.getManifest().getEntries().containsKey("Main-Class");
    } else if(1.7 == javaVersion) {
        return null != jarFile.getManifest().getMainAttributes().getValue("Main-Class");
    } else {
        //TODO JDK 8 에서는 어떻게 될까?
        log.debug("Not implements");
        return false;
    }
}

대략 위의 메서드를 통해서 선택한 jar가 실행가능한 Main-Class를 가지고 있는지 여부를 확인할 수 있다.

참고


파일을 저장할 때, 파일이 저장될 경로는 부분은 상당한 주의를 요한다. 경로에 따라서는 전혀 다른 위치가 저장될 수 있으니…
우리가 접하게 되는 운영체제에 따라서 다른 파일구분자(‘\’, ‘/‘, ‘:’)를 사용하고 있는데, 이를 문자열로 처리하기는 힘이 들다.

전에는 File.separtor’를 문자열 중간중간에 넣으면서 필요한 경로를 만들었다면,
이제는 java.nio.file 패키지에 있는 ‘Path’, ‘Paths’를 이용하여 간결하게 코드를 작성해보자.

import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertThat;

import java.io.File;
import java.nio.file.Path;
import java.nio.file.Paths;

import org.junit.Test;

public class PathTest {

    @Test
    public void testAddFileSeperator() {
        String path = "honeymon" + File.separator + "test";
        assertThat(path.toString(), is("honeymon/test"));

        path = "honeymon" + File.separator + "test" + File.separator + "file-separator";
        assertThat(path.toString(), is("honeymon/test/file-separator"));
    }

    @Test
    public void testPathsGet() {
        Path path = Paths.get("honeymon", "test");
        assertThat(path.toString(), is("honeymon/test"));

        path = Paths.get("honeymon", "test", "path");
        assertThat(path.toString(), is("honeymon/test/path"));
    }
}

파일 경로를 저렇게 만드는 이유 중 하는, 특정 위치에 파일을 생성하거나 조작하기 위해서인데 기존의 방식과 비교하면 다음처럼 파일을 다룰 수 있게 된다.

@Test
public void testMakeDir() {
    File file = new File("honeymon" + File.separator + "test" + File.separator + "file-separator");
    if(!file.exists()) {
        file.mkdir();
    }
}

@Test
public void testMakeDirByPath() {
    File file = Paths.get("honeymon", "test", "path").toFile();
    if(!file.exists()) {
        file.mkdir();
    }
}

위와 같은 형태로 차이가 생겨난다. 이 코드는 경로에 대한 변수가 증가할수록 더욱 확연한 차이를 보일 것이다. 오래전 코드를 사용하려고 하다가, 다르게 적용할 방법이 있을까하고 찾아보다가 걸린 이야기였다.

Sent from My Haroopad
The Next Document processor based on Markdown - Download

실로 오랜만에 적는 독후감(?)이다. 그 동안 이런저런 책을 읽었지만, 독후감을 써야겠다는 생각을 가지게 되는 책이 오랜만에 나타났다.

Deview 2014에 참관하러 갔다가 부스에 계신 인사이트 대표님께 인사드리면서 이야기를 하다가 가판대에 놓여있는 이 책을 발견했다. 이미 대웅에서 나온 책을 가지고 있던 상태여서 잠시 망설였지만, SNS으로 알고 계신 이병준님이 번역(http://www.buggymind.com/559)하시기도 했고 Java 7, 8 주석도 수록했다는 문구에 혹해서 그 자리에서 바로 구매했다. 결코 강요에 의해 구매한 것은 아니다.

프로그래밍을 하게 되면, 자신이 사용하고 있는 프로그래밍 언어와 관련해서 기본을 되짚어 보는 의미로 일년에 한두번 정도 읽어줘야하는 책들이 있다.



자바 쪽에서는 ‘클린코드‘, ‘Effective Java‘, ‘토비의 스프링‘ 등이 있다. Effective Java는 OO출판사에서 나온 것이 있고, 인사이트에서 이번에 출간했다. 00출판사의 서적경우에는 번역이 워낙 거시기해서 원서를 보는 것이 낫다는 평이 많은 편이다. 나 역시 읽어도 내가 읽고 있는 것이 글인지 싶을 만큼 몇줄 읽어내려가다보면 어디를 읽었는지 되짚어야할 만큼 집중도가 뚜욱 떨어진다.

인사이트에서 나온 ‘Effective Java 2nd’는 읽으면서 여러모로 흡족했다. 책크기나 종이재질도 그렇고 폰트도 그렇고.
나는 책에 줄을 치면서 책을 보는데, 책의 본문에 중요하다고 생각되는 문장마다 굵은 글씨 처리가 되어 있어서 줄을 치는 횟수가 많이 줄었다.



어쩌면 내가 허투로 보면서 넘어갈만한 요소들에도 굵은 글씨 처리가 되어 집중하게 된다. 사실 이렇게 책의 중요부분마다 굵은 글씨처리 해주는 것이 사소한듯 하지만 손이 많이 가고 번거로운 작업을 요구한다. 번역자가 그 책을 읽는 분들에게 중요하다고 알려주고 있는 것이다. 내 스타일에는 잘 어울린다.



자바 코딩과 관련된 규칙의 끝날 즈음에는 ‘요약하자면’ 으로 규칙의 내용을 간결하게 한단락으로 정리해주는 부분이 있다. 규칙을 읽어가다보면 이해가 어려웠던 부분도 ‘요약하자면’ 단락을 읽으면서 정리할 수가 있다. 쪽집게 과외 선생님이 콕하고 찝어주는 느낌이랄까?

프로그래밍을 처음 시작하면 예제를 따라서, 다른 사람의 코드를 따라서 혹은 자신만의 방법으로 코딩을 익히고 배우면서 프로그래밍을 익혀나가게 된다. 이러다보면 우리는 종종 그 프로그래밍 언어가 가지고 있는 장점과 단점, 권고사항 등을 제대로 따르지 않게되는 나쁜 습관을 가지게 되는 경우가 있다. 프로그래밍 언어에서 별다른 오류없이 컴파일되고 실행되니까 자기만의 방법으로 코딩하게 된다. 그러다보면 나쁜 냄새를 뿜어내는 프로그램이 만들어지게 될 것이다.

자바 프로그래밍을 하면서 빠지기 쉬운 착오나 자주하게 되는 실수를 짚어준다. hashCode() 메서드를 오버라이딩하면 equals() 메서드도 함께 오버라이딩 해야한다는 규칙(IDE를 사용하면 동시에 생성하도록 강제되어 있다)이라던지 등의 자바 프로그래밍과 관련된 다양한 이야기와 지식이 담겨 있다.

요약하자면, 자바 프로그래밍을 하는 이라면 책장에 꽂아두고 일년에 두번씩은 읽어줘야할 그런 책이다. 책 여기저기에 스며있는 역자의 풍부한 프로그래밍 지식이 잘 스며든 명작이 탄생했다.

꼭 사라~ 반드시 사라~


+ Recent posts