我有一个函数,它使用JPA Criteria API从数据库中检索数据,具体取决于我传递给它的一些参数。
params使用对象gridParams
传递,如下所示:
public List<MyObjectDTO> find(final GridParamsDTO gridParams) {
final CriteriaBuilder builder = getCriteriaBuilder();
final List<Predicate> predicates = new ArrayList<>();
final CriteriaQuery<MyObjectDTO> criteriaQuery = builder.createQuery(MyObjectDTO.class);
final Root<MyObject> from = criteriaQuery.from(MyObject.class);
Join<MyObject, AnotherObject> join = from.join(MyObject_.anotherObject, JoinType.LEFT);
if ((gridParams.getFilter() != null) && (gridParams.getFilter().length > 0)) {
for (final GridFilterDTO filter : gridParams.getFilter()) {
if ("fieldX".equals(filter.getField())) {
final List<Predicate> sqPredicates = new ArrayList<>();
Subquery<Long> sq = criteriaQuery.subquery(Long.class);
Root<ObjectX> sqFrom = sq.from(ObjectX.class);
sqPredicates
.add(builder.equal(sqFrom.get(ObjectX_.organismeIDE), filter.getFilterSingleValue()));
sq.select(sqFrom.get(ObjectX_.referentielID).get(MyObject_.objectX));
sq.where(builder.and(sqPredicates.toArray(new Predicate[sqPredicates.size()])));
predicates.add(builder.in(from.get(MyObject_.objectX)).value(sq));
}
if ("fieldA".equals(filter.getField()) || "fieldB".equals(filter.getField())) {
final GridFilterOperatorEnum gridFilterEnumValues = GridFilterOperatorEnum.values()[filter.getOperator().ordinal()];
switch (gridFilterEnumValues) {
case TEXT_CONTAINS:
predicates.add(builder.like(builder.upper(from.get(filter.getField())), "%" + filter.getFilterSingleValue().toUpperCase() + "%"));
break;
case TEXT_START_WITH:
predicates.add(builder.like(builder.upper(from.get(filter.getField())), filter.getFilterSingleValue().toUpperCase() + "%"));
break;
case TEXT_DIFFERENT:
predicates.add(builder.notEqual(from.get(filter.getField()), filter.getFilterSingleValue()));
break;
case TEXT_END_WITH:
predicates.add(builder.like(builder.upper(from.get(filter.getField())), "%" + filter.getFilterSingleValue().toUpperCase()));
break;
case TEXT_EQUALS:
predicates.add(builder.equal(builder.upper(from.get(filter.getField())), filter.getFilterSingleValue().toUpperCase()));
break;
default:
break;
}
}
if ("dateField1".equals(filter.getField()) || "dateField2".equals(filter.getField())) {
final GridFilterOperatorEnum gridFilterEnumValues = GridFilterOperatorEnum.values()[filter.getOperator().ordinal()];
switch (gridFilterEnumValues) {
case DATE_EQUALS:
predicates.add(builder.equal(from.<LocalDate> get(filter.getField()), LocalDate.parse(filter.getFilterSingleValue())));
break;
case DATE_BEFORE:
predicates.add(builder.lessThan(from.<LocalDate> get(filter.getField()), LocalDate.parse(filter.getFilterSingleValue())));
break;
case DATE_AFTER:
predicates.add(builder.greaterThan(from.<LocalDate> get(filter.getField()), LocalDate.parse(filter.getFilterSingleValue())));
break;
case DATE_BETWEEN:
predicates.add(
builder.between(from.<LocalDate> get(filter.getField()), LocalDate.parse(filter.getFilterSetValues()[0]),
LocalDate.parse(filter.getFilterSetValues()[1])));
break;
default:
break;
}
}
if ("anotherField".equals(filter.getField())) {
if (filter.getFilterSetValues().length > 0) {
predicates
.add(builder.isTrue(join.get(AnotherObject_.lib).in((Object[]) filter.getFilterSetValues())));
} else {
predicates.add(join.get(AnotherObject_.lib).isNull());
}
}
}
}
if (gridParams.hasSort()) {
List<Order> orderList = new ArrayList<>();
for (IGridSort gridSort : gridParams.getSort()) {
if (ArrayUtils.contains(new String[] { "fieldA", "dateField1", "dateField2", "fieldB" }, gridSort.getField())) {
if (gridSort.getSort().equalsIgnoreCase(GridSortDTO.ASC)) {
orderList.add(builder.asc(from.get(gridSort.getField())));
} else if (gridSort.getSort().equalsIgnoreCase(GridSortDTO.DESC)) {
orderList.add(builder.desc(from.get(gridSort.getField())));
}
}
if (gridSort.getField().equalsIgnoreCase("anotherField")) {
if (gridSort.getSort().equalsIgnoreCase(GridSortDTO.ASC)) {
orderList.add(builder.asc(join.get(AnotherObject_.lib)));
} else if (gridSort.getSort().equalsIgnoreCase(GridSortDTO.DESC)) {
orderList.add(builder.desc(join.get(AnotherObject_.lib)));
}
}
}
if (!orderList.isEmpty()) {
criteriaQuery.orderBy(orderList);
}
}
predicates.add(builder.between(builder.literal(LocalDate.now()), from.get(MyObject_.dateDebut),
from.get(MyObject_.dateFin)));
criteriaQuery.multiselect(from.get(MyObject_.objectX), from.get(MyObject_.dateDebut), from.get(MyObject_.dateFin),
from.get(MyObject_.lib), from.get(MyObject_.coleur), join,
from.get(MyObject_.refExterne));
criteriaQuery.where(builder.and(predicates.toArray(new Predicate[predicates.size()])));
criteriaQuery.distinct(true);
final TypedQuery<MyObjectDTO> typedQuery = getEntityManager().createQuery(criteriaQuery);
if (gridParams.hasStart()) {
typedQuery.setFirstResult(gridParams.getStartRow());
}
if (gridParams.hasEnd()) {
typedQuery.setMaxResults(gridParams.getEndRow() - Math.max(0, gridParams.getStartRow()));
}
return typedQuery.getResultList();
}
}
问题是SonarQube抱怨这种方法的循环复杂性&#34;发现&#34;是31大于30授权,我做了一些研究,我发现我必须重构我的功能,以减少Cyclomatic复杂性。
在这个函数中,我必须测试gridParams
是否定义了4个字段:(开始,结束,排序和过滤),排序和过滤器是对象数组,所以我必须迭代它们。
最终我需要查看很多字段,如果没有大量的检查,我无法看到如何做到这一点:/
我的情况如何解决这个问题?
答案 0 :(得分:1)
您可能希望首先查看Refactoring Catalog中的一些重构。
如果你看一下你的方法,你有很多部分:
这些是使用Extract Method重构重构为单独方法的理想选择。将这些部分提取到新方法后,可以对每个方法重复该过程,直到您认为已经尽可能远。然后,您可以查看已创建的新方法,并识别那些操纵相同数据的方法。他们可能希望被移动到一个单独的类,例如,一个Query类。
switch语句看起来也是替换有条件多态性重构的好候选者。
如果有疑问,请从小开始,一次进行一次简单的重构。
答案 1 :(得分:0)
以下是提取方法的方法:
public List<MyObjectDTO> find(final GridParamsDTO gridParams) {
final CriteriaBuilder builder = getCriteriaBuilder();
final CriteriaQuery<MyObjectDTO> criteriaQuery = builder.createQuery(MyObjectDTO.class);
final Root<MyObject> from = criteriaQuery.from(MyObject.class);
final Join<MyObject, AnotherObject> join = from.join(MyObject_.anotherObject, JoinType.LEFT);
final List<Order> orderList = buildOrderList(gridParams, builder, from, join);
if (!orderList.isEmpty()) {
criteriaQuery.orderBy(orderList);
}
criteriaQuery.multiselect(from.get(MyObject_.objectX),
from.get(MyObject_.dateDebut),
from.get(MyObject_.dateFin),
from.get(MyObject_.lib),
from.get(MyObject_.coleur),
join,
from.get(MyObject_.refExterne));
criteriaQuery.where(builder.and(buildPredicates(gridParams, builder, criteriaQuery, from, join)));
criteriaQuery.distinct(true);
final TypedQuery<MyObjectDTO> typedQuery = getEntityManager().createQuery(criteriaQuery);
if (gridParams.hasStart()) {
typedQuery.setFirstResult(gridParams.getStartRow());
}
if (gridParams.hasEnd()) {
typedQuery.setMaxResults(gridParams.getEndRow() - Math.max(0, gridParams.getStartRow()));
}
return typedQuery.getResultList();
}
private Predicate[] buildPredicates(final GridParamsDTO gridParams, final CriteriaBuilder builder,
final CriteriaQuery<MyObjectDTO> criteriaQuery, final Root<MyObject> from,
Join<MyObject, AnotherObject> join) {
final List<Predicate> predicates = new ArrayList<>();
final GridFilterDTO[] filters = gridParams.getFilter();
if (filters != null && filters.length > 0) {
for (final GridFilterDTO filter : filters) {
if ("fieldX".equals(filter.getField())) {
addSubQuery(builder, predicates, criteriaQuery, from, filter);
}
if ("fieldA".equals(filter.getField()) || "fieldB".equals(filter.getField())) {
addTextPredicates(builder, predicates, from, filter);
}
if ("dateField1".equals(filter.getField()) || "dateField2".equals(filter.getField())) {
addDatePredicates(builder, predicates, from, filter);
}
if ("anotherField".equals(filter.getField())) {
if (filter.getFilterSetValues().length > 0) {
predicates
.add(builder.isTrue(join.get(AnotherObject_.lib).in((Object[]) filter.getFilterSetValues())));
} else {
predicates.add(join.get(AnotherObject_.lib).isNull());
}
}
}
}
predicates.add(builder.between(builder.literal(LocalDate.now()), from.get(MyObject_.dateDebut),
from.get(MyObject_.dateFin)));
return predicates.toArray(new Predicate[predicates.size()]);
}
private void addSubQuery(final CriteriaBuilder builder, final List<Predicate> predicates,
final CriteriaQuery<MyObjectDTO> criteriaQuery, final Root<MyObject> from, final GridFilterDTO filter) {
final List<Predicate> sqPredicates = new ArrayList<>();
Subquery<Long> sq = criteriaQuery.subquery(Long.class);
Root<ObjectX> sqFrom = sq.from(ObjectX.class);
sqPredicates.add(builder.equal(sqFrom.get(ObjectX_.organismeIDE), filter.getFilterSingleValue()));
sq.select(sqFrom.get(ObjectX_.referentielID).get(MyObject_.objectX));
sq.where(builder.and(sqPredicates.toArray(new Predicate[sqPredicates.size()])));
predicates.add(builder.in(from.get(MyObject_.objectX)).value(sq));
}
private void addTextPredicates(final CriteriaBuilder builder, final List<Predicate> predicates,
final Root<MyObject> from, final GridFilterDTO filter) {
final GridFilterOperatorEnum gridFilterEnumValues = GridFilterOperatorEnum.values()[filter.getOperator().ordinal()];
switch (gridFilterEnumValues) {
case TEXT_CONTAINS:
predicates.add(builder.like(builder.upper(from.get(filter.getField())), "%" + filter.getFilterSingleValue().toUpperCase() + "%"));
break;
case TEXT_START_WITH:
predicates.add(builder.like(builder.upper(from.get(filter.getField())), filter.getFilterSingleValue().toUpperCase() + "%"));
break;
case TEXT_DIFFERENT:
predicates.add(builder.notEqual(from.get(filter.getField()), filter.getFilterSingleValue()));
break;
case TEXT_END_WITH:
predicates.add(builder.like(builder.upper(from.get(filter.getField())), "%" + filter.getFilterSingleValue().toUpperCase()));
break;
case TEXT_EQUALS:
predicates.add(builder.equal(builder.upper(from.get(filter.getField())), filter.getFilterSingleValue().toUpperCase()));
break;
default:
break;
}
}
private void addDatePredicates(final CriteriaBuilder builder, final List<Predicate> predicates,
final Root<MyObject> from, final GridFilterDTO filter) {
final GridFilterOperatorEnum gridFilterEnumValues = GridFilterOperatorEnum.values()[filter.getOperator().ordinal()];
switch (gridFilterEnumValues) {
case DATE_EQUALS:
predicates.add(builder.equal(from.<LocalDate> get(filter.getField()), LocalDate.parse(filter.getFilterSingleValue())));
break;
case DATE_BEFORE:
predicates.add(builder.lessThan(from.<LocalDate> get(filter.getField()), LocalDate.parse(filter.getFilterSingleValue())));
break;
case DATE_AFTER:
predicates.add(builder.greaterThan(from.<LocalDate> get(filter.getField()), LocalDate.parse(filter.getFilterSingleValue())));
break;
case DATE_BETWEEN:
predicates.add(
builder.between(from.<LocalDate> get(filter.getField()), LocalDate.parse(filter.getFilterSetValues()[0]),
LocalDate.parse(filter.getFilterSetValues()[1])));
break;
default:
break;
}
}
private List<Order> buildOrderList(final GridParamsDTO gridParams, final CriteriaBuilder builder,
final Root<MyObject> from, Join<MyObject, AnotherObject> join) {
if (gridParams.hasSort()) {
return Collections.emptyList();
}
List<Order> orderList = new ArrayList<>();
for (IGridSort gridSort : gridParams.getSort()) {
if (ArrayUtils.contains(new String[] { "fieldA", "dateField1", "dateField2", "fieldB" }, gridSort
.getField())) {
if (gridSort.getSort().equalsIgnoreCase(GridSortDTO.ASC)) {
orderList.add(builder.asc(from.get(gridSort.getField())));
} else if (gridSort.getSort().equalsIgnoreCase(GridSortDTO.DESC)) {
orderList.add(builder.desc(from.get(gridSort.getField())));
}
}
if (gridSort.getField().equalsIgnoreCase("anotherField")) {
if (gridSort.getSort().equalsIgnoreCase(GridSortDTO.ASC)) {
orderList.add(builder.asc(join.get(AnotherObject_.lib)));
} else if (gridSort.getSort().equalsIgnoreCase(GridSortDTO.DESC)) {
orderList.add(builder.desc(join.get(AnotherObject_.lib)));
}
}
}
return orderList;
}
现在由你来决定这是否更好。 您甚至可以提取更多方法和更多局部变量,以避免在此代码中重复过多。
答案 2 :(得分:-1)
你可以尝试这样的事情:
&#xA;&#xA; public List&lt; MyObjectDTO&gt; find(final GridParamsDTO gridParams){&#xA;&#xA; CriteriaBuilder builder = getCriteriaBuilder();&#xA;列表与LT;谓词&GT; predicates = new ArrayList&lt;&gt;();&#xA;&#xA; CriteriaQuery中&LT; MyObjectDTO&GT; criteriaQuery = builder.createQuery(MyObjectDTO.class);&#xA;&#xA;根和LT;为MyObject&GT; from = criteriaQuery.from(MyObject.class);&#xA;&#xA;加入&lt; MyObject,AnotherObject&gt; join = from.join(MyObject_.anotherObject,JoinType.LEFT);&#xA;&#xA; predicates = subMethod1(gridParams,builder,predicates,criteriaQuery,from,join);&#xA;&#xA; criteriaQuery = subMethod2(gridParams,builder,criteriaQuery,from,join);&#xA;&#xA; predicates.add(builder.between(builder.literal(LocalDate.now()),from.get(MyObject_.dateDebut),&#xA; from.get(MyObject_.dateFin)));&#xA;&#xA ; criteriaQuery.multiselect(from.get(MyObject_.objectX),from.get(MyObject_.dateDebut),from.get(MyObject_.dateFin),&#xA; from.get(MyObject_.lib),from.get(MyObject_。) coleur),join,&#xA; from.get(MyObject_.refExterne));&#xA; criteriaQuery.where(builder.and(predicates.toArray(new Predicate [predicates.size()])));&#xA; criteriaQuery.distinct(真);&#XA;&#XA;最终的TypedQuery&lt; MyObjectDTO&gt; typedQuery = getEntityManager()。createQuery(criteriaQuery);&#xA;&#xA; if(gridParams.hasStart()){&#xA; typedQuery.setFirstResult(gridParams.getStartRow());&#XA; }&#XA; if(gridParams.hasEnd()){&#xA; typedQuery.setMaxResults(gridParams.getEndRow() - Math.max(0,gridParams.getStartRow()));&#xA; }&#XA;&#XA; return typedQuery.getResultList();&#xA;}&#xA;&#xA; private CriteriaQuery&lt; MyObjectDTO&gt; subMethod2(GridParamsDTO gridParams,CriteriaBuilder构建器,&#xA; CriteriaQuery&lt; MyObjectDTO&gt; criteriaQuery,Root&lt; MyObject&gt; from,&#xA; Join&lt; MyObject,AnotherObject&gt; join){&#xA; if(gridParams.hasSort()){&#xA;列表与LT;排序&gt; orderList = new ArrayList&lt;&gt;();&#xA; for(IGridSort gridSort:gridParams.getSort()){&#xA; if(ArrayUtils.contains(new String [] {“fieldA”,“dateField1”,“dateField2”,“fieldB”},gridSort.getField())){&#xA; if(gridSort.getSort()。equalsIgnoreCase(GridSortDTO.ASC)){&#xA; orderList.add(builder.asc(from.get(gridSort.getField())));&#XA; } else if(gridSort.getSort()。equalsIgnoreCase(GridSortDTO.DESC)){&#xA; orderList.add(builder.desc(from.get(gridSort.getField())));&#XA; }&#XA; }&#XA; if(gridSort.getField()。equalsIgnoreCase(“anotherField”)){&#xA; if(gridSort.getSort()。equalsIgnoreCase(GridSortDTO.ASC)){&#xA; orderList.add(builder.asc(join.get(AnotherObject_.lib)));&#XA; } else if(gridSort.getSort()。equalsIgnoreCase(GridSortDTO.DESC)){&#xA; orderList.add(builder.desc(join.get(AnotherObject_.lib)));&#XA; }&#XA; }&#XA; }&#XA; if(!orderList.isEmpty()){&#xA; criteriaQuery.orderBy(orderList);&#XA; }&#XA; }&#XA; return criteriaQuery;&#xA;}&#xA;&#xA; private List&lt; Predicate&gt; subMethod1(GridParamsDTO gridParams,CriteriaBuilder构建器,&#xA; List&lt; Predicate&gt;谓词,CriteriaQuery&lt; MyObjectDTO&gt; criteriaQuery,Root&lt; MyObject&gt;来自&#xA; Join&lt; MyObject,AnotherObject&gt; join){&#xA; if((gridParams.getFilter()!= null)&amp;&amp;(gridParams.getFilter()。length&gt; 0)){&#xA;&#xA; for(final GridFilterDTO filter:gridParams.getFilter()){&#xA; if(“fieldX”.equals(filter.getField())){&#xA;最终列表&lt;谓词&gt; sqPredicates = new ArrayList&lt;&gt;();&#xA;子查询&LT;长&GT; sq = criteriaQuery.subquery(Long.class);&#xA;根和LT; _对象&GT; sqFrom = sq.from(ObjectX.class);&#xA; sqPredicates&#XA; .add(builder.equal(sqFrom.get(ObjectX_.organismeIDE),filter.getFilterSingleValue()));&#xA; sq.select(sqFrom.get(ObjectX_.referentielID)获得(MyObject_.objectX));&#XA; sq.where(builder.and(sqPredicates.toArray(new Predicate [sqPredicates.size()])));&#xA; predicates.add(builder.in(from.get(MyObject_.objectX))值(SQ)。);&#XA; } else if(“fieldA”.equals(filter.getField())||“fieldB”.equals(filter.getField())){&#xA; final GridFilterOperatorEnum gridFilterEnumValues = GridFilterOperatorEnum.values()[filter.getOperator()。ordinal()];&#xA; switch(gridFilterEnumValues){&#xA;案例TEXT_CONTAINS:&#xA; predicates.add(builder.like(builder.upper(from.get(filter.getField())),“%”+ filter.getFilterSingleValue()。toUpperCase()+“%”));&#xA;打破;&#XA; case TEXT_START_WITH:&#xA; predicates.add(builder.like(builder.upper(from.get(filter.getField())),filter.getFilterSingleValue()。toUpperCase()+“%”));&#xA;打破;&#XA;案例TEXT_DIFFERENT:&#xA; predicates.add(builder.notEqual(from.get(filter.getField()),filter.getFilterSingleValue()));&#xA;打破;&#XA;案例TEXT_END_WITH:&#xA; predicates.add(builder.like(builder.upper(from.get(filter.getField())),“%”+ filter.getFilterSingleValue()。toUpperCase()));&#xA;打破;&#XA;案例TEXT_EQUALS:&#xA; predicates.add(builder.equal(builder.upper(from.get(filter.getField())),filter.getFilterSingleValue()。toUpperCase()));&#xA;打破;&#XA;默认:&#XA;打破;&#XA; }&#XA; } else if(“dateField1”.equals(filter.getField())||“dateField2”.equals(filter.getField())){&#xA; final GridFilterOperatorEnum gridFilterEnumValues = GridFilterOperatorEnum.values()[filter.getOperator()。ordinal()];&#xA; switch(gridFilterEnumValues){&#xA;案例DATE_EQUALS:&#xA; predicates.add(builder.equal(from。&lt; LocalDate&gt; get(filter.getField()),LocalDate.parse(filter.getFilterSingleValue())));&#xA;打破;&#XA;案例DATE_BEFORE:&#xA; predicates.add(builder.lessThan(from。&lt; LocalDate&gt; get(filter.getField()),LocalDate.parse(filter.getFilterSingleValue())));&#xA;打破;&#XA;案例DATE_AFTER:&#xA; predicates.add(builder.greaterThan(from。&lt; LocalDate&gt; get(filter.getField()),LocalDate.parse(filter.getFilterSingleValue())));&#xA;打破;&#XA;案例DATE_BETWEEN:&#xA; predicates.add(&#xA; builder.between(from。&lt; LocalDate&gt; get(filter.getField()),LocalDate.parse(filter.getFilterSetValues()[0]),&#xA; LocalDate.parse(filter .getFilterSetValues()[1])));&#XA;打破;&#XA;默认:&#XA;打破;&#XA; }&#XA; } else if(“anotherField”.equals(filter.getField())){&#xA; if(filter.getFilterSetValues()。length&gt; 0){&#xA;谓词&#XA; .add(builder.isTrue(join.get(AnotherObject_.lib).in((Object [])filter.getFilterSetValues())));&#xA; } else {&#xA; predicates.add(join.get(AnotherObject_.lib).isNull());&#XA; }&#XA;&#XA; }&#XA; }&#XA;&#XA; }&#XA;返回谓词;&#xA;}&#xA;
&#xA;