링크 : http://isagoksu.com/2009/development/java/creating-custom-annotations-and-making-use-of-them/ 

 

How to Create a Custom Annotations?

There are a lot of documentation about this part in the Internet. All you have to do is basically creating an annotation class like below:

public @interface Copyright {
    String info() default "";
}

And that’s it. Now it’s ready to use! Now you can put copyright information to your classes :) Since we didn’t define any @Target, you can use this annotation anywhere in your classes by default. If you want your annotation to be only available for class-wise or method-wise, you should define @Target annotation. Here is a little table of what options are available:

  • @Target(ElementType.PACKAGE), package header
  • @Target(ElementType.TYPE), class header
  • @Target(ElementType.CONSTRUCTOR), constructor header
  • @Target(ElementType.METHOD), method header
  • @Target(ElementType.FIELD), for class fields only
  • @Target(ElementType.PARAMATER), for method parameters only
  • @Target(ElementType.LOCAL_VARIABLE), for local variables only

If you want your annotation to be available in more than one place, just use array syntax as in:

@Target({ ElementType.PARAMETER, ElementType.LOCAL_VARIABLE })

One thing you may already notice is annotations are interfaces, so you don’t implement anything in them.

How to Make Use of Your Custom Annotations?

Up to here, you can find lots of examples. Okaaay, now let’s do something useful :) For instance, let’s re-implement JUnit’s @Test annotation. As you guys already know, @Test annotation is a marker annotation. Basically it marks the method as test method. If you’re expecting any exceptions, you would set expect attribute in the annotation. You can try anything here, I’m just using this example since everyone knows how @Test annotation works.

First let’s define our annotation:

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Test {
    Class expected();
}

You might notice that I used @Retention. This annotation marks our annotation to be retained by JVM at runtime. This will allow us to use Java reflections later on.

Now we need to write our annotation parser class. This class will parse our annotation and trigger some other invocations related to what we want. Keep in mind that if you have more than one custom annotation, then it’s also wise to have separate parsers for each annotation you define. So I’ll create one for this! The basic idea behind the annotation parser is using Java reflections to access the annotation information/attributes etc. So here is an example parser for our @Test annotation:

public class TestAnnotationParser {
    public void parse(Class<?> clazz) throws Exception {
        Method[] methods = clazz.getMethods();
        int pass = 0;
        int fail = 0;

    for (Method method : methods) {
        if (method.isAnnotationPresent(Test.class)) {
            try {
                method.invoke(null);
                pass++;
            } catch (Exception e) {
                fail++;
            }
        }
    }
}

}

That’s all you need. You parser is ready to use too. But wait a minute, we didn’t implement anything about the annotation attributes. This part is a bit tricky. Because you cannot directly access those attributes from the object graph. Luckily invocation helps us here. You can only access these attributes by invoking them. Sometimes you might need to cast the class to the annotation type too. I’m sure you’ll figure out when you see it:) Anyways here is a bit more logic to take our expected attribute into account:

// ...
// this is how you access to the attributes
Test test = method.getAnnotation(Test.class);
// we use Class type here because our attribute type
// is class. If it would be string, you'd use string
Class expected = test.expected();
try {
    method.invoke(null);
    pass++;
} catch (Exception e) {
    if (Exception.class != expected) {
        fail++;
    } else {
        pass++;
    }
}
// ...

Now everything is ready to use. Below example demonstrates how you use Parser with your test classes:

public class Demo {
    public static void main(String [] args) {
        TestAnnotationParser parser = new TestAnnotationParser();
        parser.parse(MyTest.class);
        // you can use also Class.forName 
        // to load from file system directly!
    }
}

Yeah, I hope you enjoyed. Don’t hesitate to put some comments down if you’ve a better approach? Thanks! Here is the full parser class implementation:

public class TestAnnotationParser {
    public void parse(Class<?> clazz) throws Exception {
        Method[] methods = clazz.getMethods();
        int pass = 0;
        int fail = 0;

    for (Method method : methods) {
        if (method.isAnnotationPresent(Test.class)) {
            // this is how you access to the attributes
            Test test = method.getAnnotation(Test.class);
            Class expected = test.expected();
            try {
                method.invoke(null);
                pass++;
            } catch (Exception e) {
                if (Exception.class != expected) {
                    fail++;
                } else {
                    pass++;
                }
            }
        }
    }
}

}

Edit: Also after receiving some emails, I guess I should add a full working example :) So here is one. Just copy paste and run the show :)

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@interface Test {
    String info() default "";
}

class Annotated { @Test(info = "AWESOME") public void foo(String myParam) { System.out.println("This is " + myParam); } }

class TestAnnotationParser { public void parse(Class clazz) throws Exception { Method[] methods = clazz.getMethods();

    for (Method method : methods) {
        if (method.isAnnotationPresent(Test.class)) {
            Test test = method.getAnnotation(Test.class);
            String info = test.info();

            if ("AWESOME".equals(info)) {
                 System.out.println("info is awesome!");
                 // try to invoke the method with param
                 method.invoke(
                    Annotated.class.newInstance(), 
                    info
                 );
            }
        }
    }
}

}

public class Demo { public static void main(String[] args) throws Exception { TestAnnotationParser parser = new TestAnnotationParser(); parser.parse(Annotated.class); } }

'Java > Java' 카테고리의 다른 글

[Java] jar 파일 실행 시키기  (0) 2013.04.07
[Java] JDK Download  (0) 2013.04.02
[Java] Class<?> 의 의미?  (0) 2013.01.21
[Java] JConsole 연결 옵션  (0) 2013.01.05
[Java] Java 모니터링 툴 VisualVM Download  (0) 2012.12.28
posted by 뚱2

오늘 아이폰 기본 '사진'앱 값이 화면을 클릭하면 토글 방식으로 Status, NavigationBar, ToolBar가 사라지거나
보여지는 앱을 만들어 봤습니다.
화면을 클릭하면 이벤트를 받기위해 화면 크기 만한 UIButton을 만들고 Custom으로 설정하고  
화면에서는 보이지 않게 하기 위해서 Alpha값은 0.0으로 했습니다.

그랬더니 이상하게 이벤트가 발생하지 않았습니다.
이상해서 이리저리 해보다가 Alpha값을 0.0 초과로 지정 했더니 이벤트가 발생했습니다.
개발할때 실수 할수 있는 부분이라고 생각되어서 글 올려봅니다. 
posted by 뚱2
아이폰 앱을 보다보면은 아래 그림과 같이 반투명 뷰에 ActivityIndicator를 이용해서 화면에 뿌려주는 것을 볼수 있습니다.
궁금하기도 하고 나중에 써먹을 일이 있을것 같아서 인터넷으로 찾아봤는데 구글신이 외면했는지 못찾아서
짜집기로 직접 만들어 봤습니다.

 

//
//  UIActivityIndicatorRoundView.h
//  AlphaTest
//
//  Created by Dae Jun Ko on 11. 8. 13..
//  Copyright 2011년 __MyCompanyName__. All rights reserved.
//

#import 

#define kDefaultStrokeColor         [[UIColor blackColor] colorWithAlphaComponent:0.5]
#define kDefaultRectColor           [[UIColor blackColor] colorWithAlphaComponent:0.5]
#define kDefaultStrokeWidth         0.0
#define kDefaultCornerRadius        10.0

@interface UIActivityIndicatorRoundView : UIView

@property (nonatomic, retain) UIColor *strokeColor;
@property (nonatomic, retain) UIColor *rectColor;
@property (nonatomic, assign) CGFloat strokeWidth;
@property (nonatomic, assign) CGFloat cornerRadius;
@property (nonatomic, retain) UIActivityIndicatorView *activityIndicator;
@end


//
//  UIActivityIndicatorRoundView.m
//  AlphaTest
//
//  Created by Dae Jun Ko on 11. 8. 13..
//  Copyright 2011년 __MyCompanyName__. All rights reserved.
//

#import "UIActivityIndicatorRoundView.h"

@implementation UIActivityIndicatorRoundView

@synthesize strokeColor, rectColor;
@synthesize strokeWidth, cornerRadius;
@synthesize activityIndicator;

- (id)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        // Initialization code
        self.opaque = NO;
        self.strokeColor = kDefaultStrokeColor;
        self.rectColor = kDefaultRectColor;
        self.strokeWidth = kDefaultStrokeWidth;
        self.cornerRadius = kDefaultCornerRadius;
        
        self.activityIndicator 
        = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge];
        CGPoint mycenter;
        mycenter.x = frame.size.width/2;
        mycenter.y = frame.size.height/2;
        self.activityIndicator.center = mycenter;
        [self.activityIndicator startAnimating];
        [self addSubview:activityIndicator];
    }
    return self;
}


// Only override drawRect: if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
- (void)drawRect:(CGRect)rect
{
    CGContextRef context = UIGraphicsGetCurrentContext();
    CGContextSetLineWidth(context, strokeWidth);
    CGContextSetStrokeColorWithColor(context, self.strokeColor.CGColor);
    CGContextSetFillColorWithColor(context, self.rectColor.CGColor);
    
    CGRect rrect = self.bounds;
    
    CGFloat radius = cornerRadius;
    CGFloat width = CGRectGetWidth(rrect);
    CGFloat height = CGRectGetHeight(rrect);
    
    // Make sure corner radius isn't larger than half the shorter side
    if (radius > width/2.0)
        radius = width/2.0;
    if (radius > height/2.0)
        radius = height/2.0;    
    
    CGFloat minx = CGRectGetMinX(rrect);
    CGFloat midx = CGRectGetMidX(rrect);
    CGFloat maxx = CGRectGetMaxX(rrect);
    CGFloat miny = CGRectGetMinY(rrect);
    CGFloat midy = CGRectGetMidY(rrect);
    CGFloat maxy = CGRectGetMaxY(rrect);
    CGContextMoveToPoint(context, minx, midy);
    CGContextAddArcToPoint(context, minx, miny, midx, miny, radius);
    CGContextAddArcToPoint(context, maxx, miny, maxx, midy, radius);
    CGContextAddArcToPoint(context, maxx, maxy, midx, maxy, radius);
    CGContextAddArcToPoint(context, minx, maxy, minx, midy, radius);
    CGContextClosePath(context);
    CGContextDrawPath(context, kCGPathFillStroke);
    
    [self bringSubviewToFront:activityIndicator];
}


-(void)dealloc
{
    [activityIndicator release];
    
    [strokeColor release];
    [rectColor release];
    
    
    [super dealloc];
}

@end


// 사용법
#pragma mark-
#pragma mark clickAlert
-(IBAction)startAlert:(id)sender
{
    if ( viewAlert )
        return;
    
    CGRect frame = [self.view frame];
    CGRect newFrame;

    newFrame.size.width = frame.size.width/2;
    newFrame.size.height = frame.size.width/2;
    newFrame.origin.x = (frame.size.width - newFrame.size.width) / 2;
    newFrame.origin.y = (frame.size.height - newFrame.size.height) / 2;
    
    if ( ( viewAlert = [[UIActivityIndicatorRoundView alloc] initWithFrame:newFrame] ) )
    {   
         [self.view addSubview:viewAlert];
    }
}

-(IBAction)stopAlert:(id)sender
{
    if ( viewAlert == nil )
        return;
    
    [viewAlert removeFromSuperview];
    [viewAlert release];
    viewAlert = nil;
}
#pragma mark-


만드는 방법은 여러가지가 있겠으나 전 쿼츠를 이용해서 그렸습니다.
그리는 방법은 아이폰 예제 QuartzDemo와 http://iphonedevelopment.blogspot.com/2008/11/creating-transparent-uiviews-rounded.html를 참조했습니다.

posted by 뚱2

-(IBAction)clickedAlert1:(id)sender
{
    NSLog(@"clickedAlert1:");
    
    UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"로그인" 
                                                    message:@"\n\n\n" 
                                                   delegate:self 
                                          cancelButtonTitle:nil 
                                          otherButtonTitles:@"취소", @"확인", nil];

    // 아이디
    UITextField *fieldID = [[UITextField alloc] initWithFrame:CGRectMake(17.0, 50.0, 250.0, 30.0)];
    fieldID.backgroundColor = [UIColor whiteColor];
    fieldID.borderStyle =  UITextBorderStyleNone;
    fieldID.font = [UIFont fontWithName:@"Helvetica" size:20];
    fieldID.placeholder = @"아이디";
    fieldID.tag = 1000;
    [fieldID becomeFirstResponder]; // 첫번째에 키보드 포커스를 가게 한다.

    [alert addSubview: fieldID];
    [fieldID release];
    
    // 비밀번호
    UITextField *fieldPwd = [[UITextField alloc] initWithFrame:CGRectMake(17.0, 81.0, 250.0, 30.0)];
    fieldPwd.backgroundColor = [UIColor whiteColor];
    fieldPwd.borderStyle =  UITextBorderStyleNone;
    fieldPwd.font = [UIFont fontWithName:@"Helvetica" size:20];
    fieldPwd.placeholder = @"비밀번호";
    fieldPwd.secureTextEntry = TRUE;
    fieldPwd.tag = 1001;
    
    [alert addSubview: fieldPwd];
    [fieldPwd release];    
    
    [alert show];
    [alert release];
}


위와 같이 특정 이벤트에서 설정해주고
UIAlertViewDelegate 에서 tag값으로 컨트롤들을 가져와서 값을 읽어오면 된다. 
또한 자신의 앱에 맞게 Custom AlertView를 만들고 싶으면
UIAlertView를 상속 받고 drawRect 오버라이딩 해서 직접 그려줘야 한다. 
posted by 뚱2