2011-01-12 3 views
7

직렬화 된 데이터 스트림에서 문자열 "com.oldpackage.className"을 "com.newPackage.className"으로 바꾸려고합니다. 이 serialize 된 데이터는 DB에서 읽은 다음 문자열을 바꾼 후 업데이트됩니다.직렬화 된 데이터의 클래스 이름 바꾸기

같은 일을하는 동안 몇 가지 문제가 있습니다. 이미 짐작 하셨다면 리팩토링 연습의 일부입니다. 직렬화 된 데이터를 조작하는 데 도움이되는 라이브러리가 있습니까? 주의 사항이나주의 사항에 대해서도 의견을 말할 수 있다면 큰 도움이 될 것입니다.

고마워, 크리스. P.S : 이전 클래스와 새 클래스 모두 해당 필드의 일부로 serialversion ID를 선언하지 않습니다.

+0

합니다. com.newPack.Person이있는 사람 2) com/oldPackage/Person을 com/newPack/Person으로 바꿉니다. – ChrisOdney

+0

com.oldPackage라는 클래스가 있으므로 com/oldPackage/Person을 com/newPack/Person으로 바꿉니다.위의 작업에 영향을받는 PersonDetails가 있다면 다음을 수행합니다. 3) com.newPack.PersonDetails (결과 1)을 com.oldPackage.PersonDetails 으로 바꿉니다. 4) com/newPack/PersonDetails ((2)) with com/oldPackage/PersonDetails 누락 된 항목이 있으면 알려주세요. – ChrisOdney

답변

5

나는 당신의 시도를하는 법을 모르지만 나는 "합법적 인"해결책을 제안 할 수 있습니다. Classpath에 이전 패키지와 새 패키지가 모두있는 변환기를 구현하고 다음을 수행합니다. DB에서 데이터를 읽고 이전 패키지를 사용하여 직렬화를 해제하고 이전 인스턴스를 Java에서 새 것으로 변환 한 다음 DB에 새 데이터를 다시 저장합니다.

이 솔루션을 사용하려면 더러운 작업을 수행해야하지만 안전합니다. 또한 결과는 앞으로 재사용 될 수 있습니다. 그러나 직렬화 된 데이터에서 클래스 이름을 바꿀 수있는 솔루션을 찾기를 바랍니다.

+0

알렉스, 그건 제가 처음 접근 한 것이고 아직 살아 있습니다. 그러나 문제는 직렬화 된 데이터가 최대 절전 모드 프록시이고 첫 번째 접근 방식에 너무 많은 문제가 있습니다. 직렬화 된 데이터에서 패키지 이름을 쉽고 이론적으로 가능하게 대체하는 방법을 찾았지만, 다른 사람들이 알고있는주의 사항이나 트릭을 찾으려합니다. – ChrisOdney

+0

좋습니다, 행운을 빈다. 나는 오래되고 새로운 이름이 같은 길이라면 이름 대체가 잘 될 것이라고 생각한다. 그렇지 않으면 문제가 발생할 것으로 예상됩니다. – AlexR

+0

Spot on, 나는 JDBC뿐만 아니라 Java 측면에서나 SQL에서 대체 된 문제에 직면했다. 자바 측에서는 결과 집합과의 변환으로 인해 변환 될 수있었습니다. 내가 뱅킹하고 있던 DB에서, 당신이 언급 한 이유 때문에 정확하게 문제를 제기했습니다. – ChrisOdney

1

만약 데이터 - 투 - - 리팩토링 할 저장되는 - 문자열 형태 - 데이터베이스에 하나의 옵션은 단순히 데이터, 예를 들어, (의사의 MySQL의)

update mydata 
set serialized_data = 
replace(serialized_data, "com.oldpackage", "com.newpackage") 
을 갱신하려면 SQL을 사용하는 것입니다

물론 DB에서이 데이터를 다시 읽으려고 시도하기 전에 Java 코드를 리팩터링해야합니다.

+0

그는 직렬화 가능 자바 객체를 저장합니다. 간단한 문자열 교체가 가능합니까? 즉 자바 직렬화를 중단하지 않습니까? – AlexR

+0

DB를 사용하여 업데이트하는 것이 좋습니다. 게시판. – ChrisOdney

+1

정상적으로 작동합니다. 데이터를 다시 읽기 전에 실제 코드가 리팩터링된다는 가정과 함께 주요 문제 인 업데이트를 모순하는 직렬화 된 형식의 정보는 없습니다. 이 양식에서 데이터는 자체적으로 설명됩니다. 다른 것들이 있지만 XStream을 serializer/deserializer로 추천합니다. – kvista

2

IIRC 충분한 권한으로 ObjectInputStream.resolveClass (및 resolveProxyClass)을 대체하면 다른 패키지 이름으로 Class을 반환 할 수 있습니다. IIRC에서는 간단한 클래스 이름을 변경할 수 없습니다.

+0

Tom, Enum입니다. – ChrisOdney

+0

그리고 자바 문서에서 열거 형에 대해 말한 내용 : "enum 상수를 deserialize하는 프로세스는 사용자 정의 할 수 없습니다. enum 유형으로 정의 된 클래스 별 readObject, readObjectNoData 및 readResolve 메소드는 deserialization 중에 무시됩니다." – ChrisOdney

+0

@ChrisOdney 나는 이러한 방법을 사용하지 않을 것을 제안했습니다. –

1

다른 압정을 사용할 수 있습니까? 자바 직렬화 형식은 장기간 저장에 사용될 때 몇 가지 중요한 문제가 있습니다.

리팩토링하고 모든 저장된 데이터를 일방 또는 양방향으로 deserialise해야 할 가능성이 높기 때문에 Google Protocol Buffers을 대체 직렬화 형식으로 보길 원할 수 있습니다.

더 많은 작업이 필요할 수 있지만 장기간 저장 및 버전 관리를 위해 특별히 설계되었습니다.

정확한 톰 Hawtin의의 회신을

+0

Gareth,이 현재 데이터를 deserialize 할 때까지 대체 serialization 메커니즘을 생각할 수 없습니다. – ChrisOdney

+0

한 번 배치 작업에서 orignal 클래스를 사용 하시겠습니까? –

2

행운을 빌어 요, 나는 다음과 같은 코드를 사용하여 구현하는 관리해야 : 당신은 또한하는 readClassDescriptor을 오버라이드 (override) 할 필요가

public static ObjectInputStream getSwapOIS(InputStream in ,String fromClass,String toClass) 
    throws IOException ,ClassNotFoundException { 
    final String from="^"+fromClass,fromArray="^\\[L"+fromClass,toArray="[L"+toClass; 
    return new ObjectInputStream(in) { 
     protected Class<?> resolveClass(ObjectStreamClass desc) 
      throws IOException, ClassNotFoundException 
     { 
      String name = desc.getName().replaceFirst(from, toClass); 
      name = name.replaceFirst(fromArray, toArray); 
      return Class.forName(name); 
     } 
     protected ObjectStreamClass readClassDescriptor() 
      throws IOException, ClassNotFoundException 
     { 
      ObjectStreamClass cd = super.readClassDescriptor(); 
      String name = cd.getName().replaceFirst(from, toClass); 
      name = name.replaceFirst(fromArray, toArray); 
      if(!name.equals(cd.getName())) { 
       cd = ObjectStreamClass.lookup(Class.forName(name)); 
      } 
      return cd; 
     } 
    }; 
} 

주(). 표준 유형과 배열 모두에서 작동하며 패키지 이름뿐 아니라 클래스 이름도 변경할 수 있습니다. 그냥 수행 com.oldPackage 교체) 1 : 열거 형의 이름 com.oldPackage.Person이고 새 이름은 내가 직렬화 된 데이터로 대체해야 다른 어떤 com.newPack.Person입니다

InputStream in = new ByteArrayInputStream(classBytes); 
ObjectInputStream ois = getSwapOIS( in, 
             "com.oldpackage.className", 
             "com.newpackage.newClassName"); 
Object myObject= ois.readObject(); 
관련 문제