2012-08-31 25 views
4

我需要註釋一個具有Set<UUID>屬性的類。編組標量UUID是好的,我可以使用@DynamoDBMarshalling註釋來指定我的轉換器,並且一切正常。Java,DynamoDB:是否可以自定義一個Set?

當試圖在Set<UUID>上使用相同的轉換器時,得到「DynamoDBMappingException:期望的SS值」。我試着創建一個自定義轉換器,期望Set<UUID>,但同樣的問題仍然存在。

是否可以自定義編組?

@DynamoDBTable(tableName="djones-test") 
public class UUIDRecommendation { 
    private UUID id; 
    private Set<UUID> recommendations; 

    @DynamoDBHashKey 
    @DynamoDBMarshalling(marshallerClass=UuidConverter.class) 
    public UUID getId() { 
     return id; 
    } 

    public void setId(UUID id) { 
     this.id = id; 
    } 

    //Neither this nor UuidConverter.class work here  
    @DynamoDBMarshalling(marshallerClass=SetUuidConverter.class) 
    public Set<UUID> getRecommendations() { 
     return recommendations; 
    } 

    public void setRecommendations(Set<UUID> recommendations) { 
     this.recommendations = recommendations; 
    } 
} 

這裏的堆棧跟蹤:

com.amazonaws.services.dynamodb.datamodeling.DynamoDBMappingException: Expected SS in value {SS: [1a841b97-ab9d-4425-a2c0-f9a81bebf0b4, 1a841b97-ab9d-4425-a2c0-f9a81bebf0b4, 1a841b97-ab9d-4425-a2c0-f9a81bebf0b4], } when invoking public void com.company.model.UUIDRecommendation.setRecommendations(java.util.Set) 
    at com.amazonaws.services.dynamodb.datamodeling.SUnmarshaller.typeCheck(SUnmarshaller.java:26) 
    at com.amazonaws.services.dynamodb.datamodeling.DynamoDBMapper.setValue(DynamoDBMapper.java:329) 
    at com.amazonaws.services.dynamodb.datamodeling.DynamoDBMapper.marshallIntoObject(DynamoDBMapper.java:302) 
    at com.amazonaws.services.dynamodb.datamodeling.DynamoDBMapper.load(DynamoDBMapper.java:253) 
    at com.amazonaws.services.dynamodb.datamodeling.DynamoDBMapper.load(DynamoDBMapper.java:196) 
    at com.mendeley.service.data.DynamoRecommendedItemsDataServiceTest.testObjectMapper(DynamoRecommendedItemsDataServiceTest.java:65) 
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) 
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) 
    at java.lang.reflect.Method.invoke(Method.java:597) 
    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.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:28) 
    at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:74) 
    at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:83) 
    at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:72) 
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:231) 
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:47) 
    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:61) 
    at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:71) 
    at org.junit.runners.ParentRunner.run(ParentRunner.java:300) 
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:174) 
    at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50) 
    at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38) 
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467) 
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683) 
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390) 
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197) 

回答

2

哦,親愛的 - 看起來像臺客戶marshallers是unpossible。 AWS SDK被硬編碼爲僅處理單個字符串值(SUnmarshaller())。在AWS SDK 1.3.13,線185

DynamoDBReflector:

if (isCustomMarshaller(getter)) { 
    unmarshaller = new SUnmarshaller() { 

     @Override 
     public Object unmarshall(AttributeValue value) { 
      return getCustomMarshalledValue(toReturn, getter, value); 
     } 
    }; 
} 

UPDATE

作爲一個完全骯髒的黑客,我的東西拼湊在一起,通過複製工作/粘貼整個類:(這就是爲什麼私人靜態最終效用服務是和依賴注入是

這將起作用,所以你可以使用一個客戶轉換器(UuidConverter在我的情況下)返回UUID實例的獲取器,Set<UUID>實例。

我添加了一個名爲getCustomMarshalledValueSet的方法,該方法遍歷由value.getSS()返回的List,爲每個方法調用自定義編組器,並將結果添加到它返回的Set。

@SuppressWarnings({ "rawtypes", "unchecked" }) 
    private <T> T getCustomMarshalledValueSet(T toReturn, Method getter, AttributeValue value) { 
    DynamoDBMarshalling annotation = getter.getAnnotation(DynamoDBMarshalling.class); 
    Class<? extends DynamoDBMarshaller<? extends Object>> marshallerClass = annotation.marshallerClass(); 

    DynamoDBMarshaller marshaller; 
    try { 
     marshaller = marshallerClass.newInstance(); 
    } catch (InstantiationException e) { 
     throw new DynamoDBMappingException("Couldn't instantiate marshaller of class " + marshallerClass, e); 
    } catch (IllegalAccessException e) { 
     throw new DynamoDBMappingException("Couldn't instantiate marshaller of class " + marshallerClass, e); 
    } 

    Set<T> set = new HashSet<T>(); 

    for (String part : value.getSS()) { 
     set.add((T) marshaller.unmarshall(getter.getReturnType(), part)); 
    } 

    return (T) set; 
} 

此外getArgumentUnmarshaller改爲帶來之前有條件的isCollection檢查,以決定使用什麼類型的解組,並改變了自定義編組塊選擇正確的排序。

  if (isCustomMarshaller(getter)) { 
       if (isCollection) { 
        unmarshaller = new SSUnmarshaller() { 

         @Override 
         public Object unmarshall(AttributeValue value) { 
          return getCustomMarshalledValueSet(toReturn, getter, value); 
         } 
        }; 
       } else { 
        unmarshaller = new SUnmarshaller() { 

         @Override 
         public Object unmarshall(AttributeValue value) { 
          return getCustomMarshalledValue(toReturn, getter, value); 
         } 
        }; 
       } 

      } 
4

試試這個。它處理getter/setter中的marshall/unmarshall。我使用類似的技術來存儲包含JSON的Set<String>,但在我的代碼中將其作爲Set<CustomObject>進行訪問。我獨自離開getter/setter並使用便捷方法。

下面是修改的版本:

@DynamoDBTable(tableName="djones-test") 
public class UUIDRecommendation { 
    private String id; 
    // custom object representation in JVM 
    private Set<UUID> recommendations; 

    private static final JsonMarshaller<UUID> UUID_MARSHALLER = new JsonMarshaller<UUID>(); 

    @DynamoDBHashKey(attributeName="id") 
    public String getId() { 
     return id; 
    } 
    public void setId(String id) { 
     this.id = id; 
    } 

    // Set<String> holding JSON in DynamoDB 
    @DynamoDBAttribute(attributeName="recommendations") 
    public Set<String> getRecommendations() { 
     if (recommendations != null) { 
      Set<String> jsonSet = new HashSet<String>(recommendations.size()); 
      for (UUID recommendation : recommendations) { 
       String json = UUID_MARSHALLER.marshall(recommendation); 
       jsonSet.add(json); 
      } 
      return jsonSet; 
     } else { 
      return null; 
     } 
    } 
    public void setRecommendations(Set<String> jsonSet) { 
     if (jsonSet != null) { 
      recommendations = new HashSet<UUID>(jsonSet.size()); 
      for (String json : jsonSet) { 
       UUID recommendation = UUID_MARSHALLER.unmarshall(UUID.class, json); 
       recommendations.add(recommendation); 
      } 
     } 
    } 

    // convenience methods 
    @DynamoDBIgnore 
    public UUID convenienceMethod(UUID recommendation) { 
     return null; 
    } 

    // custom object 
    public class UUID { 

    } 
} 
+0

這很好用!這有點奇怪,他們沒有包含特定的功能,但這是一個很好的解決方法,謝謝! – GavinoGrifoni

1

See this pull requestd我連着DynamoDBReflector的修改版本,其中處理組aribtrary對象的序列化/反序列化。我一直在使用它一段時間,它的效果很好。

相關問題