Java注解

相信很多Javaer在学习Java的过程中,最先接触到的注解应该是@Override了。随着学习的深入,我们开始学习一些开源框架,比如Spring、Hibernate、MyBatis等,这就需要我们对注解有一定的了解。

1、什么是注解

注解是那些插入到代码中,使用其他工具可以对其进行处理的标签,在Java中,注解是当做一个修饰符来使用(比如public、static之类的关键词),它被放在被注解项之前。每一个注解的名称前面都加上了@符号。其实不用把注解想的太神奇,它类似于Javadoc注释,用来说明一个类的各个部分的作用,注解本身不会做任何事情,需要工具去解析才会有用。

2、自定义注解

注解是由注解接口@interface来定义的,一般注解都会有如下所示的格式:

@Target({ ElementType.FIELD, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
public @interface CustomAnnotation {

    int value();
    String name() default "[none]";

}

初看起来注解都和java的接口类似,注解里面的方法叫做注解的元素,但是一个注解方法不能有任何的参数和throws语句。上面的注解定义了两个元素。每个元素声明都具有一下两种形式:

// 不带默认值
type elementName();
// 带默认值
Type elementName() default value;
使用的时候也有几种方式
// 元素的顺序不重要
@CustomAnnotation(value = 0, name = "name")
// 如果某个元素有默认值可不列出
@CustomAnnotation(value = 0)
// 如果只有一个元素是必填的,并且名字是value,可以不指定元素名
@CustomAnnotation(0)

注解元素的类型为下列之一:

基本类型:byte、short、int、long、float、double、char、boolean。

String。

Class(具有一个可选的类型参数,例如Class<? extends OtherClass>)。

enum。

注解类型。

由上面所述的类型数组。

一个项可以具有多个注解,只要这些注解不是同一个类型即可,注解可以用来注解包、类、接口、方法、构造器、实例域、局部变量、参数变量。

3、元注解

Java提供了@Target、@Retention、@Inherited和@Documented这4个元注解,来提供新建注解时使用。

@Target元注解可以应用于一个注解,用来限制该注解可以用到哪些项上。例如

@Target({ ElementType.FIELD, ElementType.METHOD })

表明这个注解可以应用在实例域和方法上面,ElementType有以下几种常用的类型:

FIELD:实例

METHOD:方法

PARAMETER:方法或构造器参数

CONSTRUCTOR:构造器

LOCAL_VARIABLE:局部变量

ANNOTATION_TYPE:注解类型说明

PACKAGE:包

TYPE:类(包括enum)和接口

如果一个注解没有使用@Target限制,那么该注解可以应用到任何项上面,加了@Target限制之后,如果没有把注解应用到对应的项,则会导致编译器错误。

@Retention元注解用于指定注解应该保留多长时间,默认的值是RetentionPolicy.CLASS

SOURCE:不包括在类文件中,只存在源码中

CLASS:包括在类文件中,但是虚拟机不需要将它们载入

RUNTIME:包括在类文件中,虚拟机将会载入,并且可以通过反射API来获取

@Inherited元注解只能用于对类的注解,如果一个类具有@Inherited元注解,那么它的所有子类都自动具有相同的注解

@Documented元注解为像Javadoc这样的归档工具提供一些提示。对于工具开发者来所,一般很少会用到,这里就不详细说明。

4、注解处理

前文说到注解本身不会做任何事情,只是说明一个类各个部分的作用。但是配合Java的反射特性,注解可以发挥很大的作用。这里先给一个例子:

package org.jackie.annotation;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class AnnotationHandler {

    private static Logger logger = LoggerFactory.getLogger(AnnotationHandler.class);

    /**
     * 生成一个T的实例,并把V中带有PropertyMapping的属性的值付给T实例中对应的属性
     * @param source
     * @param targetClass
     * @return
     * @throws InstantiationException
     * @throws IllegalAccessException
     * @throws ClassNotFoundException
     */
    public static <V, T> T processAnnotation(V source, Class<T> targetClass) {
        T t = null;
        try {
            t = targetClass.newInstance();
        } catch (InstantiationException | IllegalAccessException e) {
            logger.error("processAnnotation方法执行出错:", e);
            throw new PropertyMappingException("对象没有默认构造器或者无法被实例化!");
        }
        AnnotationHandler.processAnnotation(source, t);
        return t;
    }

    /**
     * 把source中带有PropertyMapping的属性的值付给T中对应的属性
     * @param source
     * @param target
     * @throws InstantiationException
     * @throws IllegalAccessException
     * @throws ClassNotFoundException
     */
    public static <V, T> void processAnnotation(V source, T target) {
        Class<?> sourceClass = source.getClass();
        Field[] fileds = sourceClass.getDeclaredFields();
        if (fileds != null && fileds.length > 0) {
            for (Field filed : fileds) {
                PropertiesMapping mappings = filed.getAnnotation(PropertiesMapping.class);
                if (mappings != null) {
                    PropertyMapping[] annotations = mappings.mappings();
                    for (PropertyMapping annotation : annotations) {
                        AnnotationHandler.processPropertyMapping(annotation, filed, source, target);
                    }
                } else {
                    PropertyMapping annotation = filed.getAnnotation(PropertyMapping.class);
                    AnnotationHandler.processPropertyMapping(annotation, filed, source, target);
                }
            }
        }
    }

    private static <V, T> void processPropertyMapping(PropertyMapping annotation, Field filed, V source, T t) {
        if (annotation != null) {
            filed.setAccessible(true);
            Object filedValue = null;
            try {
                filedValue = filed.get(source);
            } catch (IllegalArgumentException | IllegalAccessException e) {
                logger.error("反射获取属性值出错:", e);
                throw new PropertyMappingException("属性不能被访问!");
            }
            if (filedValue == null) {
                return;
            }
            // 目标类属性名
            String targetPropertyName = null;
            // 目标类属性的Java类型
            Class<?> targetPropertyType = null;
            // 目标类属性的值
            Object tergetPropertyValue = null;
            Method targetGetter = null;
            Method targetSetter = null;

            Class<?> targetClass = t.getClass();
            // 获取目标属性的属性名
            String property = annotation.property();
            targetPropertyName = AnnotationConstant.STRING_DEFAULT_VALUE.equals(property) ? filed.getName() : property;
            try {
                targetGetter = targetClass.getDeclaredMethod("get" + firstLetterUpper(targetPropertyName));
            } catch (NoSuchMethodException | SecurityException e) {
                logger.error("反射获取getter出错:", e);
                throw new PropertyMappingException(targetClass.getName() + ",不存在属性:" + targetPropertyName);
            }
            // 类型转换器
            String convertorName = annotation.convertor();
            if (!AnnotationConstant.STRING_DEFAULT_VALUE.equals(convertorName)) {
                try {
                    @SuppressWarnings("unchecked")
                    Convertible<Object, ?> convertor = (Convertible<Object, ?>) Class.forName(convertorName)
                            .newInstance();
                    tergetPropertyValue = convertor.convert(filedValue);
                    targetPropertyType = tergetPropertyValue.getClass();
                } catch (InstantiationException | IllegalAccessException e) {
                    logger.error("对象没有默认构造器或者无法被实例化:", e);
                    throw new PropertyMappingException("对象没有默认构造器或者无法被实例化!");
                } catch (ClassNotFoundException e) {
                    logger.error("转换器类不存在:", e);
                    throw new PropertyMappingException("转换器类:" + convertorName + "不存在!");
                }
            } else {
                tergetPropertyValue = filedValue;
                targetPropertyType = targetGetter.getReturnType();
            }
            try {
                targetSetter = targetClass.getDeclaredMethod("set" + firstLetterUpper(targetPropertyName), targetPropertyType);
            } catch (NoSuchMethodException | SecurityException e) {
                logger.error("反射获取setter出错:", e);
                throw new PropertyMappingException("属性不存在setter!");
            }
            try {
                targetSetter.invoke(t, tergetPropertyValue);
            } catch (IllegalArgumentException | InvocationTargetException | IllegalAccessException e) {
                logger.error("反射执行invoke出错:", e);
                throw new PropertyMappingException(targetPropertyName + ",属性的值非:" + targetPropertyType);
            }
        }
    }
    
    /**
     * 首字母大写
     * 
     * @param string
     * @return
     */
    private static String firstLetterUpper(String string) {
        if (string == null) {
            return "";
        }
        char[] c = string.toCharArray();
        if (c[0] >= 'a' && c[0] <= 'z') {
            c[0] = (char) (c[0] - 32);
        }
        return new String(c);
    }

}
package org.jackie.annotation;

import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.ElementType.METHOD;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target({ FIELD, METHOD })
@Retention(RetentionPolicy.RUNTIME)
public @interface PropertyMapping {

    String property() default AnnotationConstant.STRING_DEFAULT_VALUE;

    /**
     * 指定一个实现了Convertible接口的类
     * @return
     */
    String convertor() default AnnotationConstant.STRING_DEFAULT_VALUE;

}
package org.jackie.annotation;

import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.ElementType.METHOD;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target({ FIELD, METHOD })
@Retention(RetentionPolicy.RUNTIME)
public @interface PropertiesMapping {

    PropertyMapping[] mappings();

}
package org.jackie.annotation;

public class AnnotationConstant {

    /**
     * PropertyMapping注解字符串属性的默认值
     */
    public static final String STRING_DEFAULT_VALUE = "[none]";

}
package org.jackie.annotation;

/**
 * 把源类型S,转换为目标类型T
 * @param <S>
 * @param <T>
 */
public interface Convertible<S, T> {

    T convert(S s);

}
package org.jackie.annotation;

public class PropertyMappingException extends RuntimeException {

    private static final long serialVersionUID = 1L;

    public PropertyMappingException() {
        super("属性映射异常:目标类不存在该属性!");
    }

    public PropertyMappingException(String message) {
        super(message);
    }

}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值