Question

I am trying to use the SpEL to load the same Document into different collections based on some rules that i have defined.

So to start with what i have:

-first of all the document:

@Document(collection = "#{@mySpecialProvider.getTargetCollectionName()}")
public class MongoDocument {
// some random fields go in
}

-second i have the provider bean that should provide the collection name:

@Component("mySpecialProvider")
public class MySpecialProvider {

public String getTargetCollectionName() {
// Thread local magic goes in bellow
    String targetCollectionName = (String) RequestLocalContext.getFromLocalContext("targetCollectionName");
    if (targetCollectionName == null) {
        targetCollectionName = "defaultCollection";
    }
    return targetCollectionName;
 }
}

The problem is that when i try to insert a document into a specific collection that should be generated by the provider i get the following stacktrace:

org.springframework.expression.spel.SpelEvaluationException: EL1057E:(pos 1): No bean resolver registered in the context to resolve access to bean 'mySpecialProvider'

I also tried making the spring component ApplicationContextAware but still no luck.

Was it helpful?

Solution

As i promised i am returning with an answer to my question. To have it working you need to have the following settings for the mongoTemplate bean in the application context XML file:

<mongo:db-factory dbname="${myDatabaseName.from.properties.file}" mongo-ref="mongo"/>
<bean id="mongoMappingContext" class="org.springframework.data.mongodb.core.mapping.MongoMappingContext"/>   
<bean id="mappingMongoConverter" class="org.springframework.data.mongodb.core.convert.MappingMongoConverter" c:mongoDbFactory-ref="mongoDbFactory"
            c:mappingContext-ref="mongoMappingContext"/>
<bean id="mongoTemplate" class="org.springframework.data.mongodb.core.MongoTemplate"
            c:mongoDbFactory-ref="mongoDbFactory" c:mongoConverter-ref="mappingMongoConverter"/>

And with the settings above and the solution i suggested in my question works. You can use the same domain object and store it into multiple collections based on settings of your choosing.

EDIT:

Since someone asked for it in a related question, i will also update here the logic for the ThreadLocal context:

Make a RequestLocalContext class that wraps over the following implementation:

private static final ThreadLocal<Map> CONTEXT = new ThreadLocal<Map>() {
        protected Map initialValue() {
            Map localMap = new HashMap();
            localMap.put(LocalContextKeys.CONVERSATION_CONTEXT, new HashMap());
            return localMap;
        };
    };

public static void putInLocalContext(Object key, Object value) {
    Map localMap = CONTEXT.get();
    localMap.put(key, value);
}

 public static Object getFromLocalContext(Object key) {
    Map localMap = CONTEXT.get();
    return localMap.get(key);
}

Where LocalContextKeys is an enum containing the keys allowed in the the ThreadLocal context Map. Note that the keys are user defined so feel free to put in there whatever you may need.

OTHER TIPS

You could use mongo template's method instead: save(Object objectToSave, String collectionName).

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top