java 自动注释_使用Java注解自动化处理对应关系实现注释代码化

转:http://www.cnblogs.com/lovesqcc/p/8799187.html

概述

假设我们要从一个 ES 索引(相当于一张DB表)查询数据,ES表有 order_no, order_type, state 等字段, 而应用对象则有属性 orderNo, orderType, state等。这样,就会面临“将应用对象的属性与ES字段对应起来”的问题。

固然可以通过注释来说明,不过这样显得比较生硬。因为注释并不起实际作用,代码里还得写一套映射关系,就会存在注释与代码不一致的情况。 那么,是否可以将这种对应关系的注释用代码形式来解决呢? Java 注解可以解决这个问题。

实现

定义注解

首先定义注解类。注解类需要提供对应的ES字段名 name、类型 type 以及是否必传 required。

@Retention 指明注解在何时起作用,这里是在运行时。

@Target 指明注解应用于何种对象,这里应用于字段。

@Retention(RetentionPolicy.RUNTIME)

@Target(ElementType.FIELD)

@Documented

public @interface EsField {

/**

* 对应的ES字段名

*/

String name();

/**

* 对应的ES字段的值类型

* @return

*/

String type() default "";

/**

* 是否必传

*/

boolean required() default false;

}

应用领域对象

接着,将注解应用到应用领域对象。为简洁,应用领域对象只有四个字段。

@Data

public class CustomerDomain implements DomainSearch {

/** 店铺ID */

@EsField(name="shop_id", required = true)

private Long shopId;

/** 订单编号 */

@EsField(name="order_no")

private String orderNo;

/** 订单状态 */

@EsField(name="state", type="list")

private List state;

/** 订单类型 */

@EsField(name="order_type", type="list")

private List orderType;

}

注解解析器

接着,需要提供注解解析器,将对应的映射关系转成ES查询对象的一部分。

使用接口的默认方法来实现,是为了支持不同的业务类自动可以转化为ES查询串;

注解解析器需要使用Java反射机制,来获取相应的字段,以及字段上的注解定义,然后根据字段的类型、值、注解定义来做相应处理;

使用反射来处理字段时,由于字段一般是私有的,因此必须先设置为可访问的,处理完成后还原为不可访问;

EsField field = f.getAnnotation(EsField.class) 用来获取字段上的注解信息(name, type, required);Object value = f.get(customerDomain) 用来获取字段的值;字段的其他类型信息可以通过 Field 的方法拿到。

public interface DomainSearch {

Log logger = LogFactory.getLog(DomainSearch.class);

default String toEsQuery() {

Object customerDomain = this;

EsQuery esQuery = new EsQuery();

Field[] fields = this.getClass().getDeclaredFields();

for (Field f: fields) {

try {

if (Modifier.isStatic(f.getModifiers())) {

continue;

}

f.setAccessible(true);

Object value = f.get(customerDomain);

if (f.getAnnotation(EsField.class) != null) {

EsField field = f.getAnnotation(EsField.class);

if (field.required() && value == null) {

throw new RuntimeException("field '" + field + "' is required. value is null");

}

if (isNeedOmitted(value)) {

f.setAccessible(false);

continue;

}

if ((value instanceof List) && ((List)value).size() == 1) {

// 针对 List 中单个值做优化查询

esQuery = esQuery.addTermFilter(field.name(), ((List)value).get(0));

}

else {

esQuery = esQuery.addTermFilter(field.name(), value);

}

}

f.setAccessible(false);

} catch (Exception ex) {

logger.error("failed to build es query for field: " + f.getName(), ex);

throw new RuntimeException(ex.getCause());

}

}

return esQuery.toJsonString();

}

/**

* 判断是否需要忽略该字段的查询

* @param value 字段值

* @return 是否要忽略

*/

default boolean isNeedOmitted(Object value) {

if (value == null) {

return true;

}

// 空字符串搜索值忽略

if ((value instanceof String) && StringUtils.isBlank(value.toString())) {

return true;

}

// 空列表串忽略

if ((value instanceof List) && ((List)value).isEmpty()) {

return true;

}

return false;

}

}

查询对象

ES查询对象将所有生成的查询条件转化为ES可以接受的查询字符串。

public class EsQuery {

private static int DEFAULT_SIZE = 100;

private final Map termFilter;

private final Map rangeFilter;

private final Map matchFilter;

private int size;

private String orderBy = null;

private String order = null;

// query 查询语法, 是否需要 filtered, filter 这两层

// 5.x 版本不再需要这两层

private boolean isNeedFilterLayer = true;

private Integer from;

private final Map mustNotTermFilter;

private final Map shouldTermFilter;

private Integer shouldMatchMinimum;

private List includes;

private List excludes;

public EsQuery() {

this.termFilter = new HashMap<>();

this.rangeFilter = new HashMap();

this.matchFilter = new HashMap();

this.mustNotTermFilter = new HashMap<>();

this.shouldTermFilter = new HashedMap();

this.size = DEFAULT_SIZE;

this.includes = new ArrayList<>();

this.excludes = new ArrayList<>();

}

public EsQuery addTermFilter(String key, Object value) {

this.termFilter.put(key, value);

return this;

}

public EsQuery addMustNotTermFilter(String key, Object value) {

this.mustNotTermFilter.put(key, value);

return this;

}

public EsQuery addAllMustNotTermFilter(Map mustNot) {

if (mustNot != null && !mustNot.isEmpty()) {

this.mustNotTermFilter.putAll(mustNot);

}

return this;

}

public EsQuery addShouldTermFilter(String key, Object value) {

this.shouldTermFilter.put(key, value);

return this;

}

public EsQuery addAllShouldTermFilter(Map should) {

if (should != null && !should.isEmpty()) {

this.shouldTermFilter.putAll(should);

}

return this;

}

public EsQuery addRangeFilter(String key, long gte, long lte){

this.rangeFilter.put(key, new Range(gte, lte));

return this;

}

public EsQuery addMatchFilter(String key, Match value) {

this.matchFilter.put(key, value);

return this;

}

public EsQuery addIncludeFields(List includes) {

this.includes.addAll(includes);

return this;

}

public EsQuery addExcludeFields(List excludes) {

this.excludes.addAll(excludes);

return this;

}

@Override

public String toString() {

return toJsonString();

}

public String toJsonString() {

Map finalQuery = new HashMap<>();

Map queryMap = new HashMap<>();

Map filteredMap = new HashMap<>();

Map filterMap = new HashMap<>();

Map boolMap = new HashMap<>();

List mustList = obtainTermFilterList(this.termFilter);

List mustNotList = obtainTermFilterList(this.mustNotTermFilter);

List shouldList = obtainTermFilterList(this.shouldTermFilter);

if(!this.rangeFilter.isEmpty()){

for(Map.Entry e: this.rangeFilter.entrySet()){

Map rangeMap = new HashMap<>();

Map rangeEntityMap = new HashMap<>();

rangeEntityMap.put(e.getKey(), e.getValue().toMap());

rangeMap.put(Constant.range, rangeEntityMap);

mustList.add(rangeMap);

}

}

if(!this.matchFilter.isEmpty()){

this.matchFilter.forEach(

(key, match) -> {

Map matchEntityMap = new HashMap<>();

Map matchMap = new HashMap<>();

Map subMatchMap = new HashMap<>();

matchEntityMap.put(Constant.query, match.getQuery());

matchEntityMap.put(Constant.should_minum, match.getMinimumShouldMatch());

matchMap.put(key, matchEntityMap);

subMatchMap.put(Constant.match, matchMap);

mustList.add(subMatchMap);

});

}

boolMap.put(Constant.must, mustList);

if (!mustNotList.isEmpty())

boolMap.put(Constant.mustNot, mustNotList);

if (!shouldList.isEmpty()) {

// 有 minimum_should_match 不带过滤器

boolMap.put(Constant.should, shouldList);

boolMap.put(Constant.should_minum, shouldMatchMinimum);

queryMap.put(Constant.bool, boolMap);

}

else {

if (isNeedFilterLayer) {

filterMap.put(Constant.bool, boolMap);

filteredMap.put(Constant.filter, filterMap);

queryMap.put(Constant.filtered, filteredMap);

}

else {

queryMap.put(Constant.bool, boolMap);

}

}

finalQuery.put(Constant.query, queryMap);

Map orderMap = new HashMap<>();

Map orderItem = new HashMap<>();

if(order != null && orderBy != null){

orderItem.put(Constant.order, this.order);

orderMap.put(this.orderBy, orderItem);

finalQuery.put(Constant.sort, orderMap);

}

Map source = new HashMap<>();

if (!includes.isEmpty()) {

source.put(Constant.includes, this.includes);

}

if (!excludes.isEmpty()) {

source.put(Constant.excludes, this.excludes);

}

if (!source.isEmpty()) {

finalQuery.put(Constant.source, source);

}

finalQuery.put(Constant.size, this.size);

if (from != null) {

finalQuery.put(Constant.from, from.intValue());

}

return JSON.toJSONString(finalQuery);

}

public List obtainTermFilterList(Map termFilter) {

List termFilterList = new ArrayList<>();

for (Map.Entry e: termFilter.entrySet()){

Map termMap = new HashMap<>();

Map itemMap = new HashMap<>();

itemMap.put(e.getKey(), e.getValue());

if(e.getValue() instanceof List){

termMap.put(Constant.terms, itemMap);

}else{

termMap.put(Constant.term, itemMap);

}

termFilterList.add(termMap);

}

return termFilterList;

}

public String getOrderBy() {

return orderBy;

}

publicvoidsetOrderBy(String orderBy) {

this.orderBy = orderBy;

}

public String getOrder() {

return order;

}

publicvoidsetOrder(String order) {

this.order = order;

}

publicintgetSize() {

return size;

}

publicvoidsetSize(int size) {

this.size = size;

}

public Integer getFrom() {

return from;

}

publicvoidsetFrom(Integer from) {

this.from = from;

}

public Map getTermFilter() {

return Collections.unmodifiableMap(termFilter);

}

public Map getRangeFilter() {

return Collections.unmodifiableMap(rangeFilter);

}

public Map getMustNotTermFilter() {

return Collections.unmodifiableMap(mustNotTermFilter);

}

public Map getShouldTermFilter() {

return Collections.unmodifiableMap(shouldTermFilter);

}

public Map getMatchFilter() {

return matchFilter;

}

publicvoidsetShouldMatchMinimum(Integer shouldMatchMinimum) {

this.shouldMatchMinimum = shouldMatchMinimum;

}

public Integer getShouldMatchMinimum() {

return shouldMatchMinimum;

}

public Map getRangeMap(String key) {

return Collections.unmodifiableMap(rangeFilter.get(key).toMap());

}

public List getIncludes() {

return Collections.unmodifiableList(includes);

}

publicbooleanisNeedFilterLayer() {

return isNeedFilterLayer;

}

publicvoidsetNeedFilterLayer(boolean needFilterLayer) {

isNeedFilterLayer = needFilterLayer;

}

@Override

publicbooleanequals(Object o) {

// for you to write

}

@Override

publicinthashCode() {

// for you to write

}

小结

通过ES搜索示例,展示了如何运用注解自动化处理领域对象属性与底层ES存储字段之间的对应关系。实际上,如果想为应用对象或组件添加某种说明或注释,不妨先想想是否可以通过注解自动化处理。注解亦可用于框架自动处理对象与组件的集成。Spring框架的Resource, Component, AOP,以及 Plugin 化设计思想等都是好的应用例子。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值