MongoDB
 sql >> Base de Dados >  >> NoSQL >> MongoDB

Recuperando a chave específica do MongoDB de DuplicateKeyException que foi realmente duplicada (Java/Spring)


Na verdade não, pois o Mongo Java Driver já expõe o último erro como uma String construída:

writeResult.getLastError().get("err") retorna algo como:

insertDocument :: caused by :: 11000 E11000 duplicate key error index: test.person.$username dup key: { : "joe" }

Isso também é verdade para o shell e todos os drivers, imagino.

Uma solução razoável, eu acho, é analisar essa exceção de chave duplicada usando uma exceção personalizada:
public class DetailedDuplicateKeyException extends DuplicateKeyException {
    public DetailedDuplicateKeyException(String msg) {
        // Instead of just calling super parse the message here.
        super(msg);
    }
}

... um tradutor de exceção personalizado:
public class DetailedDuplicateKeyExceptionTransaltor extends MongoExceptionTranslator {

    @Override
    public DataAccessException translateExceptionIfPossible(RuntimeException ex) {
        if (ex instanceof MongoException.DuplicateKey) {
            return new DetailedDuplicateKeyException(ex.getMessage());
        }
        return super.translateExceptionIfPossible(ex);
    }
}

... e definindo a configuração do Spring corretamente:
@Bean
public MongoFactoryBean mongo() {
    MongoFactoryBean mongo = new MongoFactoryBean();
    mongo.setExceptionTranslator(new DetailedDuplicateKeyExceptionTransaltor());
    mongo.setHost("localhost");
    return mongo;
}

EDITAR


Após inspecionar MongoTemplate code (1.4.1.RELEASE), parece que internamente um SimpleMongoDbFactory é usado para recuperar um padrão MongoExceptionTranslator , então aquele criado com MongoFactoryBean está sombreado. Tinha perdido essa parte.

A solução é substituir SimpleMongoDbFactory (esqueça sobre MongoFactoryBean , é inútil neste contexto):
public class MySimpleMongoDbFactory extends SimpleMongoDbFactory {

    PersistenceExceptionTranslator translator = new       
            DetailedDuplicateKeyExceptionTransaltor();

    public MySimpleMongoDbFactory(Mongo mongo, String databaseName) {
        super(mongo, databaseName);
    }

    @Override
    public PersistenceExceptionTranslator getExceptionTranslator() {
        return translator;
    }
}

Agora você pode construir um modelo usando o MongoDbFactory personalizado :

template = new MongoTemplate (new MySimpleMongoDbFactory(new MongoClient(), "test"));

Tinha tentado, e este funciona para mim.