복붙노트

[SPRING] 봄 데이터를 사용하여 널 포인터 예외 예외 Mongo 집계 가져 오기 (동적 필드)

SPRING

봄 데이터를 사용하여 널 포인터 예외 예외 Mongo 집계 가져 오기 (동적 필드)

이것은 나의 Mongo Pojo도 getters와 세터 (추가되지 않음)입니다.

    @CompoundIndex(name = "account_date_idx", def = "{'account' : 1, 'date' : 1}", unique = true)
@Document(collection = "agent_data_storage")
public class AgentDataStorage extends MongoKeyedEntity<String> implements Serializable {

  public static final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
  @Field
  private Long account;

  @Field()
  private String date;

  @Field
  private Map<String, Double> dataPoints = new HashMap<>();

  public AgentDataStorage() {
  }

  public AgentDataStorage(Long account) {
    this.account = account;
    this.date = dateFormat.format(new Date());
    for (AgentDataPoints dataPoint : EnumSet.allOf(AgentDataPoints.class)) {
      this.dataPoints.put(dataPoint.toString(), 0d);
    }
  }

  public AgentDataStorage(String account) {
    this.account = Long.valueOf(account);
    for (AgentDataPoints dataPoint : EnumSet.allOf(AgentDataPoints.class)) {
      this.dataPoints.put(dataPoint.toString(), 0d);
    }
  }

  public AgentDataStorage(Long account, Date date) {
    this.account = account;
    this.date = dateFormat.format(date);
    for (AgentDataPoints dataPoint : EnumSet.allOf(AgentDataPoints.class)) {
      this.dataPoints.put(dataPoint.toString(), 0d);
    }
  }

  public AgentDataStorage(Long account, Date date, Map<String, Double> dataPoints) {
    this.account = account;
    this.date = dateFormat.format(date);
    this.dataPoints = dataPoints;
  }

  public AgentDataStorage(Long account, String date, Map<String, Double> dataPoints) {
    this.account = account;
    this.date = date;
    this.dataPoints = dataPoints;
  }

  public AgentDataStorage(String account, Date date) {
    this.account = Long.valueOf(account);
    this.date = dateFormat.format(date);
    for (AgentDataPoints dataPoint : EnumSet.allOf(AgentDataPoints.class)) {
      this.dataPoints.put(dataPoint.toString(), 0d);
    }
  }

  public AgentDataStorage(String account, String date) {
    this.account = Long.valueOf(account);
    this.date = date;
    for (AgentDataPoints dataPoint : EnumSet.allOf(AgentDataPoints.class)) {
      this.dataPoints.put(dataPoint.toString(), 0d);
    }
  }

  public Long getAccount() {
    return account;
  }

  public void setAccount(Long account) {
    this.account = account;
  }

  public Date getDate() throws ParseException {
    return dateFormat.parse(this.date);
  }

  public void setDate(Date date) {
    this.date = dateFormat.format(date);
  }

  public Map<String, Double> getDataPoints() {
    return dataPoints;
  }

  public void setDataPoints(Map<String, Double> dataPoints) {
    this.dataPoints = dataPoints;
  }

  public void updateDataPoint(AgentDataPoints agentDataPoints, Double value) {
    this.dataPoints.put(String.valueOf(agentDataPoints), value);
  }

  @Override
  public String toString() {
    final StringBuilder sb = new StringBuilder("AgentDataStorage{");
    sb.append("account=").append(account);
    sb.append(", date=").append(date);
    sb.append(", dataPoints=").append(dataPoints);
    sb.append('}');
    return sb.toString();
  }
}

집계를 시도하는 동안 null 포인터 예외가 발생하는 동안 아래는 테스트 케이스입니다.

     @Test
  public void aggregationTest() {
    Long account = 12121l;
    String startDay = "2016-01-01";
    String endDay = "2016-01-03";

    Aggregation aggregation = Aggregation
        .newAggregation(match(Criteria.where("account").is(account).and("date")
            .gte(startDay).lte(endDay)),
            group("account").sum("dataPoints.TOTAL_BUS_COMMISSION").as("total"));
    AggregationResults<AggregationResult> results = mongoTemplate.aggregate(aggregation,
        AgentDataStorage.class, AggregationResult.class);

  }

내 AggregationResult 클래스는 -

public class AggregationResult {

  private Long _id;

  private Double total;

  public Long get_id() {
    return _id;
  }

  public void set_id(Long _id) {
    this._id = _id;
  }

  public Double getTotal() {
    return total;
  }

  public void setTotal(Double total) {
    this.total = total;
  }
}

다음은 스택 추적 오류입니다.

java.lang.NullPointerException
    at org.springframework.data.mapping.context.AbstractMappingContext.getPersistentPropertyPath(AbstractMappingContext.java:233)
    at org.springframework.data.mapping.context.AbstractMappingContext.getPersistentPropertyPath(AbstractMappingContext.java:214)
    at org.springframework.data.mapping.context.AbstractMappingContext.getPersistentPropertyPath(AbstractMappingContext.java:210)
    at org.springframework.data.mongodb.core.aggregation.TypeBasedAggregationOperationContext.getReferenceFor(TypeBasedAggregationOperationContext.java:96)
    at org.springframework.data.mongodb.core.aggregation.TypeBasedAggregationOperationContext.getReference(TypeBasedAggregationOperationContext.java:91)
    at org.springframework.data.mongodb.core.aggregation.GroupOperation$Operation.getValue(GroupOperation.java:434)
    at org.springframework.data.mongodb.core.aggregation.GroupOperation$Operation.toDBObject(GroupOperation.java:416)
    at org.springframework.data.mongodb.core.aggregation.GroupOperation.toDBObject(GroupOperation.java:361)
    at org.springframework.data.mongodb.core.aggregation.Aggregation.toDbObject(Aggregation.java:331)
    at org.springframework.data.mongodb.core.MongoTemplate.aggregate(MongoTemplate.java:1500)
    at org.springframework.data.mongodb.core.MongoTemplate.aggregate(MongoTemplate.java:1435)
    at psl.service.core.agentanalytics.internal.AgentAnalyticsServiceTest.aggregationTest(AgentAnalyticsServiceTest.java:132)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:45)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:42)
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20)
    at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:72)
    at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:81)
    at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:72)
    at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:263)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:216)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:82)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:231)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:60)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:229)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:50)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:222)
    at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:60)
    at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:67)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:300)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:162)
    at org.junit.runner.JUnitCore.run(JUnitCore.java:157)
    at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:119)
    at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:42)
    at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:234)
    at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:74)

또한 내부 스프링 용기를 디버깅하려고 시도했는데, DoubleMapping의 경우 AbstractMappingContext.java 내부에서 null을 던지지 만 왜 그런 일이 일어나는지 이해할 수는 없습니다. mongo 같은 쿼리가 mongo 콘솔에서 작동합니다.

db.getCollection('agent_data_storage').aggregate([ 
{ "$match" : { "account" : 12121 , "date" : { "$gte" : "2016-01-01" , "$lte" : "2016-01-03"}}} 
, { "$group" : { "_id" : "$account" , "total" : { "$sum" : "$dataPoints.TOTAL_BUS_COMMISSION"}}}])

위 쿼리의 결과는 다음과 같습니다.

 {
    "_id" : NumberLong(12121),
    "total" : 402.0
}

모든 종류의 도움말에 감사드립니다.

AgentDataStorage-

{
    "_id" : ObjectId("586233e3fb94f6f5640196cf"),
    "account" : NumberLong(12121),
    "date" : "2016-01-01",
    "dataPoints" : {
        "TOTAL_BUS_COMMISSION" : 0.0
    }
}

해결법

  1. ==============================

    1.기본적으로 입력 유형 (AgentDataStorage)의 속성 참조를 필드 이름으로 변환하려고하는 집계의 유형화 된 집계 변형을 사용하지 말고 dataPoints.TOTAL_BUS_COMMISSION의 경우 속성 참조를 찾지 못하면 실패합니다.

    기본적으로 입력 유형 (AgentDataStorage)의 속성 참조를 필드 이름으로 변환하려고하는 집계의 유형화 된 집계 변형을 사용하지 말고 dataPoints.TOTAL_BUS_COMMISSION의 경우 속성 참조를 찾지 못하면 실패합니다.

    용도

    AggregationResults<AggregationResult> results = mongoTemplate.aggregate(aggregation,
        "agent_data_storage", AggregationResult.class);
    
  2. from https://stackoverflow.com/questions/41346329/getting-null-pointer-exception-mongo-aggregation-using-spring-datadynamic-field by cc-by-sa and MIT license