1

새로운 스프링 애플리케이션을 설계하고 개발할 때 기술적 인 이유로 인해 MongoDB를 퍼시스턴스 레이어로 사용하고 있습니다. 이것은 내가 Value Objects를 포함한 몇 가지 DDD 원칙을 구현하려는 첫 번째 프로젝트입니다. 사실 단순히 String 인 ValueObject를 저장하는 가장 좋은 방법을 찾으려고합니다. Lombok의 @Value를 사용하여 Spring REST Controller는 RestController 측에서 ValueObject로 값을 파싱합니다. 그러나 값을 저장하면 MongoDB 측에서 체계적으로 저장됩니다. 예를 들어스프링과 MongoDB : 좀 더 편평한 방법으로 값 객체를 저장하기

내 VO :

@Value 
public class PersonKey { 
    private String value; 
} 

문서 내가 MongoDB를에 저장됩니다 : MongoDB에 저장됩니다 무엇

@Document 
public class PersonDocument { 
    private PersonKey personKey; 
    private Name name; 
    ... 
} 

:

{.. "personKey": {"value": "faeeaf2"} ...} 

내가 실제로 무엇을 개미 :

최소한의 추가 상용구 코드 물론
{.. "personKey": "faeeaf2" ..} 

.. :-)

+0

'PHP'에서는 모든 'insert','update'와'find' mongodb 연산에 대해 호출되는 변환기 클래스를 작성했습니다. 이 변환기는 재귀 적이며 반사를 사용합니다. –

+0

동적 언어 인 PHP입니다. 내가 정적 언어로 자바를 위해 다르다 daresay :-) – Kristof

+0

그 이유는 내가 대답을 제공하지 않았습니다. 어쩌면 당신을 도울 것입니다. –

답변

1

그것은 당신의 유일한 옵션은 변환 후 DBObject을 수정 onAfterConvert 방법 AbstractMongoEventListener를 사용하는 것 같다. 유감스럽게도 문서에서 단일 입력란의 전환을 쉽게 변경할 수는 없습니다. 사용자 지정 변환기는 단일 필드가 아닌 전체 문서를 저장할 때 사용됩니다. getter 메소드를 사용하여 필드 액세스를 대체 할 수도 없습니다 ("객체의 필드는 문서의 필드로 변환하거나 필드에서 변환하는 데 사용됩니다. public JavaBean 속성은 사용되지 않습니다."http://docs.spring.io/spring-data/data-mongo/docs/1.4.2.RELEASE/reference/html/mapping-chapter.html). 그래서, 당신이 원하는 것을 성취 할 수있는 유일한 방법은 몽고 사건을 통해서입니다. 그러나 이벤트 핸들러에서 리플렉션을 사용하여 필드에 @Value 주석이 추가되었는지 확인할 수 있으므로 좀 더 일반적인 방법으로 변환 할 수 있습니다. @Value 주석이있는 경우 DBObject에서 value 속성으로 바꿉니다.

이렇게하려면 AbstractMongoEventListener을 확장해야합니다. 당신은 onBeforeSave 이벤트 핸들러 여기 예제를 볼 수 있습니다

https://github.com/ttrelle/spring-data-examples/blob/master/springdata-mongodb/src/main/java/mongodb/OrderBeforeSaveListener.java

업데이트 : @maartinus이 @Value 객체가 작동하지 않습니다 위해는 사용할 수 없습니다 때문에, 검색 반사를 사용하여, 코멘트에 주목로 런타임 (보존 설정은 SOURCE). 따라서 객체의 값을 반환하는 단일 메서드 value()과 함께 자신의 특수 효과 또는 인터페이스 (예 : ValueObject)를 도입해야합니다.

+0

'@lombok.Value'에 대한 확인은'@Remote (RetentionPolicy.SOURCE)'처럼 작동하지 않습니다. – maaartinus

+1

@maaartinus 맞아, 내 대답을 업데이트 할게. –

0

필자는 정확하게 똑같은 문제를 해결하기 위해 노력하고 있습니다. 그리고 실제로 CustomConverters를 사용하여이 작업을 수행 할 수 있습니다. 아마도 당신이 원하는 것과 같지는 않지만 매우 비슷한 방식 일 것입니다. 극복 할 수없는 유일한 문제는 런타임에 동적으로 변환기를 선택할 수 없다는 것입니다. 이는 라인 번호 182CustomConversions#registerConversion을 구현했기 때문입니다.

이 예제는 현재 내가 작업하고있는 것을 보여줍니다. GenericConverter을 사용하고 있지만 Converters으로 폴백 할 수도 있습니다. 이 예에서는 필드 주석을 확인하지 않습니다. 오히려 SingleValue이라는 인터페이스를 사용합니다.단일 값을 나타내는 모든 Value Object가이 인터페이스를 구현합니다. 필드에 대한 주석이 필요 없습니다.

@Configuration 
@Slf4j 
public class MongoDbConfiguration { 

    @Bean 
    @Primary 
    public CustomConversions mongoCustomConversions() throws Exception { 
     final List converterList = new ArrayList<>(); 
     converterList.add(new SingleValueConverter()); 
     return new CustomConversions(converterList); 
    } 

    private static class SingleValueConverter implements GenericConverter { 

     @Override 
     public Set<ConvertiblePair> getConvertibleTypes() { 
      return new HashSet<>(Arrays.asList(new ConvertiblePair[]{ 
        new ConvertiblePair(UUIDEntityReference.class, String.class), 
        new ConvertiblePair(String.class, FundingProcessId.class) 
        // put here all of your type conversions (two way!) 
      })); 
     } 

     @Override 
     public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) { 
      try { 
       // first check if the instance of this type is an instance of our 'SingleValue' interface 
       if (source instanceof SingleValue) { 
        return ((SingleValue) source).getValue(); 
       } 

       final Class<?> objectType = targetType.getType(); 
       final Constructor<?> constructor = objectType.getConstructor(sourceType.getType()); 
       return constructor.newInstance(source); 
      } catch (ReflectiveOperationException e) { 
       throw new RuntimeException("Could not convert unexpected type " + 
         sourceType.getObjectType().getName() + " to " + targetType.getObjectType().getName(), e); 
      } 
     } 
    } 
} 

내가 알 수있는 가장 우아한 방법입니다. 모든 유형의 등록을 자동화하는 방법을 찾고 있습니다. 이것은 어노테이션과 클래스 패스 스캐닝에서 가능할 수 있습니다. 이 구현은 일

당신은 방법 인터페이스 SingleValue
  1. 의 몇 가지를 가정합니다

    주 getValue

  2. 당신의 "단일 값 '값 클래스의 각각의 하나의 인자를 가진 생성자가 내부 유형 표현 (예 : UUID의 문자열)

EDIT : 잘못된 예제 코드를 게시했습니다. 업데이트 됨

관련 문제