2015-06-26 124 views
0

我有一個類來保存一些JSON數據如下:GSON類轉換異常

package org.swx.nursing.tools.configuration.data; 

import java.util.Set; 

import com.cerner.system.exception.Verifier; 
import com.cerner.system.exception.VerifyException; 
import com.google.common.collect.ImmutableSet; 

/** 
* Class representing a simple {@link JsonData#identifier}, 
* {@link JsonData#data} format. This class can be used to 
* persist application data for example in a Configuration file. 
* 
* @author SW029693 
* @since v1.0 
*/ 
public class JsonData <T>{ 
/** 
* Represents a unique identifier 
*/ 
private String identifier; 
/** 
* Represents the data pertaining to this {@link JsonData#identifier} 
*/ 
private T data; 

private static final Set<String> VALID_JSON_ID_TYPES = ImmutableSet.of("CONFIG","HOTKEYS"); 

public JsonData(String identifier, T data) { 
    super(); 
    this.identifier = identifier; 
    this.data = data; 
} 

/** 
* Getter for {@link JsonData#identifier} 
* @return 
*/ 
public String getIdentifier() { 
    return identifier; 
} 

/** 
* Sets the {@link JsonData#identifier} to the given value 
* @param identifier 
*   Represents a unique {@link JsonData#identifier} 
* @throws VerifyException 
*   If the argument is {@code null} or {@code empty} 
*/ 
public void setIdentifier(String identifier) throws VerifyException{ 
    Verifier.verifyNotNull(identifier, "identifier : null"); 
    Verifier.verifyNotEmpty(identifier,"identifier : empty"); 
    this.identifier = identifier; 
} 

/** 
* Getter for {@link JsonData} 
* @return 
*/ 
public T getData() { 
    return data; 
} 

/** 
* Sets the {@link JsonData#data} to the given value 
* @param identifier 
*   Represents a unique {@link JsonData#data} 
* @throws VerifyException 
*   If the argument is {@code null} 
*/ 
public void setData(T data) { 
    Verifier.verifyNotNull(data, "data : null"); 
    this.data = data; 
} 

@Override 
public String toString() { 
    return "JsonData [identifier=" + identifier + ", data=" + data + "]"; 
} 
} 

我想一些數據轉換成JSON(它寫到文件中),讀取它丟在以上JsonData對象。這是我的單元測試,失敗:

@Test 
@SuppressWarnings("unchecked") 
public void testWriteContentsToFile() { 
    ConfigurationManager<JsonData> configurationManager = (ConfigurationManager<JsonData>) 
    ConfigurationManager.Factory.create(); 
    assertNotNull(configurationManager); 
    configurationManager.write(getMockJsonData()); 
    System.out.println("1="+getMockJsonData().getData().toString()); 

    assertEquals(getMockJsonData().getData(), ((JsonData) readconfigFile()).getData()); 
} 

的輔助方法本次測試如下:

/** 
* Helper method to read the config.json file 
* @return 
*/ 
private static JsonData<ConfigurationProperty> readconfigFile() { 
    Reader reader = null; 
    JsonData<ConfigurationProperty> data = null; 
    Gson gson = null; 
    try { 
     reader = new FileReader("./config.json"); 
     gson = new GsonBuilder().create(); 
     data = gson.fromJson(reader, JsonData.class); 
     System.out.println("yooo="+data.getData().getRunnableContext()); 
    } catch (FileNotFoundException e) { 
     e.printStackTrace(); 
     fail("Test failed while reading the config.json file: "+e.getMessage());  } 
    finally { 
     try { 
      reader.close(); 
     } catch (IOException e) { 
      e.printStackTrace(); 
      fail("Test failed while reading the config.json file: "+e.getMessage()); 
     } 
    } 
    return data; 
} 

/** 
* Helper method which creates a mock {@link JsonData} object for testing purposes 
* 
* @return An instance of the newly created mock {@link Jsondata} object 
*/ 
private static JsonData<ConfigurationProperty> getMockJsonData() { 
    JsonData<ConfigurationProperty> data = new JsonData<ConfigurationProperty>("CONFIG", 
      getMockConfigurationProperty("testKey", "testContext", "APPLICATION")); 
    System.out.println("data ==="+data); 
    return data; 
} 

/** 
* Helper method which creates a {@link ConfigurationProperty} based on the given 
* non-null and non-empty arguments. This method can be used to get the 
* {@link ConfigurationProperty} instance created with the desired fields when ALL 
* of the 3 parameters are non-null, non-empty & valid. 
* 
* @param mockHotKey 
*   A non-null & non-empty mockHotkey parameter passed in as an argument 
* 
* @param mockContext 
*   A non-null & non-empty mockContext parameter passed in as an argument 
* 
* @param mockContextType 
*   A non-null & non-empty mockContextType parameter passed in as an argument 
*   
* @throws VerifierException 
*   If the argument validation for non-null or non-empty arguments as failed. 
* 
* @throws IllegalArgumentException 
*   The {@link ConfigurationProperty.Builder#withRunnableContextType(String type) method 
*   throws an {@link IllegalArgumentException} if the provided type is not supported in 
*   {@link ConfigurationProperty#RUNNABLE_CONTEXT_TYPE} 
*   
* @return An instance of newly created {@link ConfigurationProperty} object 
*/ 
private static ConfigurationProperty getMockConfigurationProperty (
     String mockHotKey, String mockContext, String mockContextType) { 
    Verifier.verifyNotNull(mockHotKey); 
    Verifier.verifyNotNull(mockContext); 
    Verifier.verifyNotNull(mockContextType); 
    Verifier.verifyNotEmpty(mockHotKey); 
    Verifier.verifyNotEmpty(mockContext); 
    Verifier.verifyNotEmpty(mockContextType); 
    return ConfigurationProperty.Builder 
       .create() 
       .withHotKey(mockHotKey) 
       .withRunnableContext(mockContext) 
       .withRunnableContextType(mockContextType) 
       .build(); 
} 

當我運行我收到以下錯誤單元測試將數據從json文件讀入到我的JsonData對象中:

java.lang.ClassCastException: com.google.gson.internal.LinkedTreeMap cannot be cast to org.swx.nursing.tools.configuration.data.ConfigurationProperty 
at org.swx.nursing.tools.configuration.data.ConfigurationManagerImplTest.readconfigFile(ConfigurationManagerImplTest.java:181) 
at org.swx.nursing.tools.configuration.data.ConfigurationManagerImplTest.testWriteContentsToFile(ConfigurationManagerImplTest.java:166) 
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.internal.runners.TestMethod.invoke(TestMethod.java:66) 
at org.jmock.integration.junit4.JMock$1.invoke(JMock.java:37) 
at org.junit.internal.runners.MethodRoadie.runTestMethod(MethodRoadie.java:105) 
at org.junit.internal.runners.MethodRoadie$2.run(MethodRoadie.java:86) 
at org.junit.internal.runners.MethodRoadie.runBeforesThenTestThenAfters(MethodRoadie.java:94) 
at org.junit.internal.runners.MethodRoadie.runTest(MethodRoadie.java:84) 
at org.junit.internal.runners.MethodRoadie.run(MethodRoadie.java:49) 
at org.junit.internal.runners.JUnit4ClassRunner.invokeTestMethod(JUnit4ClassRunner.java:98) 
at org.junit.internal.runners.JUnit4ClassRunner.runMethods(JUnit4ClassRunner.java:61) 
at org.junit.internal.runners.JUnit4ClassRunner$1.run(JUnit4ClassRunner.java:54) 
at org.junit.internal.runners.ClassRoadie.runUnprotected(ClassRoadie.java:34) 
at org.junit.internal.runners.ClassRoadie.runProtected(ClassRoadie.java:44) 
at org.junit.internal.runners.JUnit4ClassRunner.run(JUnit4ClassRunner.java:52) 
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:49) 
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) 

的文件被寫成這樣:

{ 
"identifier": "CONFIG", 
"data": { 
    "hotKey": "testKey", 
    "type": "APPLICATION", 
    "runnableContext": "testContext" 
} 
} 

我無法讀取寫入文件到JsonData對象上面JSON的「數據」部分原因是上述錯誤。

請告知

感謝

回答

1

請參閱https://sites.google.com/site/gson/gson-user-guide#TOC-Serializing-and-Deserializing-Generic-Types

當你調用的toJSON(OBJ),GSON調用obj.getClass()來獲取上的字段信息進行序列化。同樣,您通常可以在fromJson(json,MyClass.class)方法中傳遞MyClass.class對象。如果對象是非泛型類型,這工作正常。但是,如果對象是泛型類型,那麼由於Java類型擦除,泛型類型信息會丟失。這裏是表示點的例子:

class Foo<T> { 
    T value; 
} 
Gson gson = new Gson(); 
Foo<Bar> foo = new Foo<Bar>(); 
gson.toJson(foo); // May not serialize foo.value correctly 

gson.fromJson(json, foo.getClass()); // Fails to deserialize foo.value as Bar 

上述代碼失敗,因爲GSON調用list.getClass()來獲得它的類的信息以解譯值作爲類型欄,但此方法返回一個原始類,讓Foo.class 。這意味着Gson無法知道這是Foo類型的對象,而不僅僅是普通的Foo。

您可以通過爲您的泛型指定正確的參數化類型來解決此問題。您可以通過使用TypeToken類來完成此操作。

Type fooType = new TypeToken<Foo<Bar>>() {}.getType(); 
gson.toJson(foo, fooType); 

gson.fromJson(json, fooType); 

用於獲取fooType成語實際上定義含有方法GetType(匿名本地內部類),它返回完全參數化的類型。