2017-01-31 1 views
0

구성 파일 용 추상 클래스가 있습니다.이 클래스는 많은 다른 클래스로 확장 할 수 있습니다. 나는 JSON에 쓰기 위해 시스템을 작동시킬 수 있었지만, 이제는 load 함수가 필요하다. 내가 할 것입니다 내 메인 클래스에서Gson Java - JSON의 하위 클래스

public class ExampleConfig extends Configuration { 

    private static transient ExampleConfig i = new ExampleConfig(); 
    public static ExampleConfig get() { return i; } 

    @Expose public String ServerID = UUID.randomUUID().toString(); 

} 

:

ExampleConfig.get().load(); 
System.out.println(ExampleConfig.get().ServerID); 

이하지 않는 다음은 연장 클래스의 예입니다

public class Configuration { 

    public boolean load(){ 
     FileReader reader = new FileReader(this.getClass().getSimpleName() + ".json"); 
     Gson gson = new Gson(); 
     gson.fromJson(reader, this.getClass()); 
     reader.close(); 
     /** Doesn't give an error, but doesn't set any info to the child class */ 
    } 

    public boolean save(){ 
     FileWriter writer = new FileWriter(this.getClass().getSimpleName() + ".json"); 
     Gson gson = new Gson(); 
     gson.toJson(this, writer); 
     writer.close(); 
     /** This all works fine. */ 
    } 

} 

:

다음은 일반적인 구성 클래스의 오류는 있지만 JSON에서로드 한 클래스도 없습니다. JSON 파일에서로드하려는 경우에도 임의의 UUID를 계속 출력합니다. 아마 하위 클래스의 잘못된 인스턴스를 얻고있을 것이지만이를 수정하는 방법에 대한 아이디어가 없습니다. (자바 this = gson.fromJson(...)처럼 아무것도 지원할 수 없습니다. 당신은 당신의 구성 인스턴스에 읽기 값을 할당이 누락

+1

'gson.fromJson (reader, this.getClass());'- 값이 손실되는 곳입니다. 'fromJson' 메소드는 어딘가에 할당해야하는 _new_ 값을 반환합니다. –

+0

의미가 있습니다. 현재 예제를 사용하면 어떻게됩니까? –

답변

1

. gson.fromJson(.....);에서 this이 작동하지 않는 사용 및 GSON은 새로운 값을 반환 할 수 있으며, 기존 패치 수 없습니다.을 아래는 일종의 Gson 해킹입니다. 실제로는 일 필요가있는 경우에만 사용하십시오. 코드를 다시 디자인하고 구성 객체와 구성 판독기/작성기를 분리하는 것이 좋습니다. 두 개만 있습니다. 기술적 인 관점에서 충돌하는 다른 것들. 리팩토링의 결과로, 일단 당신이 설정의 인스턴스를 얻었 으면, 그것을 다른 곳에서 유지하기 위해 작가에게 위임해라. ACK, 그럼 그냥 독자의 인스턴스를 얻을 구성 값을 읽고 구성에 할당처럼, (구성이 싱글은 기억이다) : 적어도이 코드가 다른 두 가지를 함께 사용하지 않는

final ConfigurationWriter writer = getConfigurationWriter(); 
writer.write(ExampleConfig.get()); 
... 
final ConfigurationReader reader = getConfigurationReader(); 
ExampleConfig.set(reader.read(ExampleConfig.class)); 

, reader.read의 결과가 이되도록 명시 적으로을 읽고 구성 싱글 톤에 지정합니다. 당신이 악마의 문을 열고 있기 때문에 해킹의 코드 작업을 할 좋은 경우

, 당신은 GSON을 속이고 현재 구성 인스턴스을 패치하기 위해 GSON TypeAdapterFactory를 사용할 수 있습니다.

abstract class Configuration { 

    private static final Gson saveGson = new Gson(); 

    public final void load() 
      throws IOException { 
     try (final FileReader reader = new FileReader(getTargetName())) { 
      // You have to instantiate Gson every time (unless you use caching strategies) in order to let it be *specifically* be aware of the current 
      // Configuration instance class. Thus you cannot make it a static field. 
      final Gson loadGson = new GsonBuilder() 
        .registerTypeAdapterFactory(new TypeAdapterFactory() { 
         // A Gson way to denote a type since Configuration.class may not be enough and it also works with generics 
         private final TypeToken<Configuration> configurationTypeToken = new TypeToken<Configuration>() { 
         }; 

         @Override 
         @SuppressWarnings("deprecation") // isAssignableFrom is deprecated 
         public <T> TypeAdapter<T> create(final Gson gson, final TypeToken<T> typeToken) { 
          // Checking if the type token represents a parent class for the given configuration 
          // If yes, then we cheat... 
          if (configurationTypeToken.isAssignableFrom(typeToken)) { 
           // The map that's artificially bound as great cheating to a current configuration instance 
           final Map<Type, InstanceCreator<?>> instanceCreators = bindInstance(typeToken.getType(), Configuration.this); 
           // A factory used by Gson internally, we're intruding into its heart 
           final ConstructorConstructor constructorConstructor = new ConstructorConstructor(instanceCreators); 
           final TypeAdapterFactory delegatedTypeAdapterFactory = new ReflectiveTypeAdapterFactory(
             constructorConstructor, 
             gson.fieldNamingStrategy(), 
             gson.excluder(), 
             new JsonAdapterAnnotationTypeAdapterFactory(constructorConstructor) 
           ); 
           // Since the only thing necessary here is to define how to instantiate an object 
           // (and we just give it an already-existing instance) 
           // ... just delegate the job to Gson -- it would think as if it's creating a new instance. 
           // Actually it won't create one, but would "patch" the current instance 
           return delegatedTypeAdapterFactory.create(gson, typeToken); 
          } 
          // Otherwise returning a null means looking up for an existing type adapter from how Gson is configured 
          return null; 
         } 
        }) 
        .create(); 
      // The value is still loaded to nowhere, however. 
      // The type adapter factory is tightly bound to an existing configuration instance via ConstructorConstructor 
      // This is actually another code smell... 
      loadGson.fromJson(reader, getClass()); 
     } 
    } 

    public final void save() 
      throws IOException { 
     try (final FileWriter writer = new FileWriter(getTargetName())) { 
      saveGson.toJson(this, writer); 
     } 
    } 

    private String getTargetName() { 
     return getClass().getSimpleName() + ".json"; 
    } 

    private static Map<Type, InstanceCreator<?>> bindInstance(final Type type, final Configuration existingConfiguration) { 
     return singletonMap(type, new InstanceCreator<Object>() { 
      @Override 
      public Object createInstance(final Type t) { 
       return t.equals(type) ? existingConfiguration : null; // don't know if null is allowed here though 
      } 
     }); 
    } 

} 

위의 코드에있는 내용이 모두 포함되기를 바랍니다. 위에서 말했듯이 조금 더 멋진 코드를 사용하려는 의도 때문에 필요하다고 생각하지 않습니다. java.util.Properties을로드하고 저장할 수 있다고 주장 할 수 있습니다. 예, 그렇습니다. 그러나 java.util.Properties은 디자인 상 해당 속성을 반복 할 수 있으며 언제 어디서나 속성을 읽고 쓸 수 있습니다. Gson은 후드 아래의 필드를 들여다 보는 방식 인 리플렉션을 사용합니다. 이는 잘 디자인 된 객체에서 굉장합니다. 리팩토링과 데이터/데이터 작성자/리더라는 두 가지 개념이 필요합니다.