programing

Spring data MongoDb: MappingMongoConverter remove_class

firstcheck 2023. 6. 2. 22:38
반응형

Spring data MongoDb: MappingMongoConverter remove_class

기본 MappingMongoConverter는 데이터베이스의 각 개체에 사용자 지정 유형 키("_class")를 추가합니다.사용자를 작성한 경우:

package my.dto;
public class Person {
    String name;
    public Person(String name) {
        this.name = name; 
    }
}

데이터베이스에 저장합니다.

MongoOperations ops = new MongoTemplate(new Mongo(), "users");
ops.insert(new Person("Joe"));

mongo의 결과 객체는 다음과 같습니다.

{ "_id" : ObjectId("4e2ca049744e664eba9d1e11"), "_class" : "my.dto.Person", "name" : "Joe" }

질문:

  1. 사용자 클래스를 다른 네임스페이스로 이동하면 어떤 의미가 있습니까?

  2. 사용자 클래스 전용 변환기를 작성하지 않고 "_class" 키로 개체를 오염시키지 않을 수 있습니까?

여기서 이야기가 나옵니다. 실제로 인스턴스화할 클래스를 암시하기 위해 기본적으로 유형을 추가합니다.문서를 읽으려면 형식을 파이프로 연결해야 하기 때문에MongoTemplate어쨌든 두 가지 가능한 옵션이 있습니다.

  1. 실제 저장된 유형을 할당할 수 있는 유형을 입력합니다.이 경우 저장된 유형을 고려하여 개체 생성에 사용합니다.여기서 고전적인 예는 다형성 쿼리를 수행하는 것입니다.추상적인 수업이 있다고 가정합니다.Contact그리고 당신의Person그러면 다음을 쿼리할 수 있습니다.Contact그리고 우리는 본질적으로 인스턴스화할 유형을 결정해야 합니다.
  2. 반면에 완전히 다른 유형으로 전달하면 실제로 문서에 저장된 유형이 아닌 해당 유형으로 정리됩니다.그러면 유형을 이동하면 어떤 일이 발생하는지에 대한 질문이 포함됩니다.

유형 정보를 실제 유형으로 전환하는 일종의 플러그형 유형 매핑 전략을 다루는 이 티켓을 보는 것에 관심이 있을 수 있습니다.이렇게 하면 정규화된 긴 클래스 이름을 몇 글자의 해시로 줄일 수 있기 때문에 공간을 절약할 수 있습니다.또한 다른 데이터스토어 클라이언트에서 생성한 완전한 임의 유형의 키를 찾아 Java 유형에 바인딩할 수 있는 보다 복잡한 마이그레이션 시나리오도 가능합니다.

여기 제 주석이 있습니다. 효과가 있습니다.

@Configuration
public class AppMongoConfig {

    public @Bean
    MongoDbFactory mongoDbFactory() throws Exception {
        return new SimpleMongoDbFactory(new Mongo(), "databasename");
    }

    public @Bean
    MongoTemplate mongoTemplate() throws Exception {

        //remove _class
        MappingMongoConverter converter = new MappingMongoConverter(mongoDbFactory(), new MongoMappingContext());
        converter.setTypeMapper(new DefaultMongoTypeMapper(null));

        MongoTemplate mongoTemplate = new MongoTemplate(mongoDbFactory(), converter);

        return mongoTemplate;

    }

}

사용하지 않으려면_class기본적으로 속성이지만 지정된 클래스에 대한 폴리모피즘을 보존합니다. 유형을 명시적으로 정의할 수 있습니다._class(선택사항) 필드를 구성합니다.

@Bean
public MongoTemplate mongoTemplate() throws Exception {
    Map<Class<?>, String> typeMapperMap = new HashMap<>();
    typeMapperMap.put(com.acme.domain.SomeDocument.class, "role");

    TypeInformationMapper typeMapper1 = new ConfigurableTypeInformationMapper(typeMapperMap);

    MongoTypeMapper typeMapper = new DefaultMongoTypeMapper(DefaultMongoTypeMapper.DEFAULT_TYPE_KEY, Arrays.asList(typeMapper1));
    MappingMongoConverter converter = new MappingMongoConverter(mongoDbFactory(), new MongoMappingContext());
    converter.setTypeMapper(typeMapper);

    MongoTemplate mongoTemplate = new MongoTemplate(mongoDbFactory(), converter);
    return mongoTemplate;
}

이것은 보존될 것입니다._class지정된 도면요소에 대해서만 필드(또는 생성자에서 이름을 지정할 항목)를 입력합니다.

직접 작성할 수도 있습니다.TypeInformationMapper예를 들어 주석을 기반으로 합니다.문서에 주석을 다는 경우@DocumentType("aliasName")당신은 클래스의 별칭을 유지함으로써 다형성을 유지할 것입니다.

제 블로그에서 간단히 설명했지만, 여기 몇 가지 빠른 코드가 있습니다: https://gist.github.com/athlan/6497c74cc515131e1336 .

<mongo:mongo host="hostname" port="27017">
<mongo:options
...options...
</mongo:mongo>
<mongo:db-factory dbname="databasename" username="user" password="pass"                     mongo-ref="mongo"/>
<bean id="mongoTypeMapper"     class="org.springframework.data.mongodb.core.convert.DefaultMongoTypeMapper">
<constructor-arg name="typeKey"><null/></constructor-arg>
</bean>
<bean id="mongoMappingContext"      class="org.springframework.data.mongodb.core.mapping.MongoMappingContext" />
<bean id="mongoConverter"     class="org.springframework.data.mongodb.core.convert.MappingMongoConverter">
<constructor-arg name="mongoDbFactory" ref="mongoDbFactory" />
<constructor-arg name="mappingContext" ref="mongoMappingContext" />
<property name="typeMapper" ref="mongoTypeMapper"></property>
</bean>
<bean id="mongoTemplate" class="org.springframework.data.mongodb.core.MongoTemplate">
<constructor-arg name="mongoDbFactory" ref="mongoDbFactory"/>
<constructor-arg name="mongoConverter" ref="mongoConverter" />
<property name="writeResultChecking" value="EXCEPTION" /> 
</bean>

Mkyong의 답변은 여전히 유효하지만, 몇 비트가 사용되지 않고 정리 단계에 있을 수 있으므로 제 버전의 솔루션을 추가하고 싶습니다.

예:MappingMongoConverter(mongoDbFactory(), new MongoMappingContext())을 위해 더 이상 사용하지 않습니다.new MappingMongoConverter(dbRefResolver, new MongoMappingContext());그리고.SimpleMongoDbFactory(new Mongo(), "databasename");에찬여하에 new SimpleMongoDbFactory(new MongoClient(), database);.

따라서 사용 중지 경고가 없는 제 최종 작업 답변은 다음과 같습니다.

@Configuration
public class SpringMongoConfig {

    @Value("${spring.data.mongodb.database}")
    private String database;

    @Autowired
    private MongoDbFactory mongoDbFactory;

    public @Bean MongoDbFactory mongoDBFactory() throws Exception {
        return new SimpleMongoDbFactory(new MongoClient(), database);
    }

    public @Bean MongoTemplate mongoTemplate() throws Exception {

        DbRefResolver dbRefResolver = new DefaultDbRefResolver(mongoDbFactory);

        // Remove _class
        MappingMongoConverter converter = new MappingMongoConverter(dbRefResolver, new MongoMappingContext());
        converter.setTypeMapper(new DefaultMongoTypeMapper(null));

        return new MongoTemplate(mongoDBFactory(), converter);

    }

}

이것이 폐지 경고 없이 깨끗한 수업을 원하는 사람들에게 도움이 되기를 바랍니다.

부츠용 스링츠부용프츠2.3.0.RELEASE더 , 그냥 하세요.mongoTemplate이미 유형 매퍼를 설정하는 데 필요한 모든 것이 있습니다.다음 예를 참조하십시오.

@Configuration
@EnableMongoRepositories(
// your package ...
)
public class MongoConfig extends AbstractMongoClientConfiguration {

    // .....

    @Override
    public MongoTemplate mongoTemplate(MongoDatabaseFactory databaseFactory, MappingMongoConverter converter) {
        // remove __class field from mongo
        converter.setTypeMapper(new DefaultMongoTypeMapper(null));
        return super.mongoTemplate(databaseFactory, converter);
    }

    // .....

}

이것이 저의 한 줄 솔루션입니다.

@Bean 
public MongoTemplate mongoTemplateFraud() throws UnknownHostException {

  MongoTemplate mongoTemplate = new MongoTemplate(getMongoClient(), dbName);
  ((MappingMongoConverter)mongoTemplate.getConverter()).setTypeMapper(new DefaultMongoTypeMapper(null));//removes _class
  return mongoTemplate;
}

저는 이 문제로 오랫동안 고생했습니다.저는 mkyong의 접근법을 따랐지만, 제가 소개했을 때는.LocalDate 8의) "(Java 8" JSR310)"입니다.

org.springframework.core.convert.ConverterNotFoundException:
No converter found capable of converting from type [java.time.LocalDate] to type [java.util.Date]

변환기 해 변 기org.springframework.format.datetime.standard.DateTimeConvertersSpring 4.1은 Spring Data MongoDB 1.7은 Spring 4.1입니다. 최신 버전을 사용해도 컨버터가 작동하지 않습니다.

▁the다▁to▁the▁was▁use▁existing니▁solution것을 사용하는 것이었습니다.MappingMongoConverter그리고 새로운 것만 제공합니다.DefaultMongoTypeMapper 중입니다 (mkyong 중입다니트멘코드코는의:)다▁from▁(니중입)):

@Configuration
@EnableMongoRepositories
class BatchInfrastructureConfig extends AbstractMongoConfiguration
{
    @Override
    protected String getDatabaseName() {
        return "yourdb"
    }

    @Override
    Mongo mongo() throws Exception {
        new Mongo()
    }

    @Bean MongoTemplate mongoTemplate()
    {
        // overwrite type mapper to get rid of the _class column
//      get the converter from the base class instead of creating it
//      def converter = new MappingMongoConverter(mongoDbFactory(), new MongoMappingContext())
        def converter = mappingMongoConverter()
        converter.typeMapper = new DefaultMongoTypeMapper(null)

        // create & return template
        new MongoTemplate(mongoDbFactory(), converter)
    }

요약:

  • 확장하다, 하다, 확대하다AbstractMongoConfiguration
  • 으로주다는으로 을 달다.EnableMongoRepositories
  • mongoTemplate됩니다.

사용 중:

package YOUR_PACKAGE;

import javax.annotation.PostConstruct;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.mongodb.core.convert.DefaultMongoTypeMapper;
import org.springframework.data.mongodb.core.convert.MappingMongoConverter;

@Configuration
public class MongoConfiguration {


  @Autowired
  private MappingMongoConverter mongoConverter;

  @PostConstruct
  public void setUpMongoEscapeCharacterAndTypeMapperConversion() {
      mongoConverter.setMapKeyDotReplacement("_");
      
      // This will remove _class: key
      mongoConverter.setTypeMapper(new DefaultMongoTypeMapper(null));
  }

}

Btw: 또한 "."를 "_"로 대체하고 있습니다.

@Configuration
public class MongoConfig {

    @Value("${spring.data.mongodb.database}")
    private String database;

    @Value("${spring.data.mongodb.host}")
    private String host;

    public @Bean MongoDbFactory mongoDbFactory() throws Exception {
        return new SimpleMongoDbFactory(new MongoClient(host), database);
    }

    public @Bean MongoTemplate mongoTemplate() throws Exception {

        MappingMongoConverter converter = new MappingMongoConverter(new DefaultDbRefResolver(mongoDbFactory()),
                new MongoMappingContext());
        converter.setTypeMapper(new DefaultMongoTypeMapper(null));

        MongoTemplate mongoTemplate = new MongoTemplate(mongoDbFactory(), converter);

        return mongoTemplate;

    }

}

위의 정답은 사용되지 않는 종속성을 여러 개 사용하는 것 같습니다.예를 들어 코드를 확인하면 최신 Spring 릴리스에서 사용되지 않는 MongoDbFactory가 표시됩니다.2020년에 Spring-Data와 함께 MongoDB를 사용하고 있다면 이 솔루션은 더 오래된 것 같습니다.즉각적인 결과를 얻으려면 이 코드 조각을 확인하십시오.100% 작동합니다.새 AppConfig.java 파일을 만들고 이 코드 블록을 붙여넣기만 하면 됩니다.MongoDB 문서에서 "_class" 속성이 사라지는 것을 볼 수 있습니다.

package "Your Package Name";

import org.apache.naming.factory.BeanFactory;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;  
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.convert.CustomConversions;
import org.springframework.data.mongodb.MongoDatabaseFactory;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.convert.DbRefResolver;
import org.springframework.data.mongodb.core.convert.DefaultDbRefResolver;
import org.springframework.data.mongodb.core.convert.DefaultMongoTypeMapper;
import org.springframework.data.mongodb.core.convert.MappingMongoConverter;
import org.springframework.data.mongodb.core.mapping.MongoMappingContext;

@Configuration
public class AppConfig {

@Autowired
MongoDatabaseFactory mongoDbFactory;
@Autowired
MongoMappingContext mongoMappingContext;

@Bean
public MappingMongoConverter mappingMongoConverter() {

    DbRefResolver dbRefResolver = new DefaultDbRefResolver(mongoDbFactory);
    MappingMongoConverter converter = new MappingMongoConverter(dbRefResolver, mongoMappingContext);
    converter.setTypeMapper(new DefaultMongoTypeMapper(null));

    return converter;
    }

}

유형 매퍼를 변경하는 클래스 정의에 @TypeAlias 주석을 추가하기만 하면 됩니다.

는 감사와 어느 것도 것 .MongoCustomConversions

저에게 맞는 솔루션은 다음과 같습니다.

@Configuration
public class MongoConfig {

    @Bean
    public MappingMongoConverter mappingMongoConverterWithCustomTypeMapper(
            MongoDatabaseFactory factory,
            MongoMappingContext context,
            MongoCustomConversions conversions) {
        DbRefResolver dbRefResolver = new DefaultDbRefResolver(factory);
        MappingMongoConverter mappingConverter = new MappingMongoConverter(dbRefResolver, context);
        mappingConverter.setCustomConversions(conversions);

        /**
         * replicate the way that Spring
         * instantiates a {@link DefaultMongoTypeMapper}
         * in {@link MappingMongoConverter#MappingMongoConverter(DbRefResolver, MappingContext)}
         */
        CustomMongoTypeMapper customTypeMapper = new CustomMongoTypeMapper(
                context,
                mappingConverter::getWriteTarget);
        mappingConverter.setTypeMapper(customTypeMapper);
        return mappingConverter;
    }
}

public class CustomMongoTypeMapper extends DefaultMongoTypeMapper {

    public CustomMongoTypeMapper(
            MappingContext<? extends PersistentEntity<?, ?>, ?> mappingContext,
            UnaryOperator<Class<?>> writeTarget) {
        super(DefaultMongoTypeMapper.DEFAULT_TYPE_KEY, mappingContext, writeTarget);
    } 

    @Override
    public TypeInformation<?> readType(Bson source) {

    /**
     * do your conversion here, and eventually return
     */
    return super.readType(source);
    }
}

은 대으로사수있다니습용할다을을 할 수 .BeanPostProcessormappingMongoConverter변환기를 거기에 추가합니다.

비슷한 것

public class MappingMongoConverterHook implements BeanPostProcessor {
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        if ("mappingMongoConverter" == beanName) {
            ((MappingMongoConverter) bean).setTypeMapper(new CustomMongoTypeMapper());
        }
        return bean;
    }
}

언급URL : https://stackoverflow.com/questions/6810488/spring-data-mongodb-mappingmongoconverter-remove-class

반응형