protected void writeInternal(@Nullable Object obj, Bson bson, @Nullable MongoPersistentEntity<?> entity) { if (obj == null) { return; } if (null == entity) { throw new MappingException("No mapping metadata found for entity of type " + obj.getClass().getName()); } PersistentPropertyAccessor<?> accessor = entity.getPropertyAccessor(obj); DocumentAccessor dbObjectAccessor = new DocumentAccessor(bson); MongoPersistentProperty idProperty = entity.getIdProperty(); if (idProperty != null && !dbObjectAccessor.hasValue(idProperty)) { Object value = idMapper.convertId(accessor.getProperty(idProperty), idProperty.getFieldType()); if (value != null) { dbObjectAccessor.put(idProperty, value); } } writeProperties(bson, entity, accessor, dbObjectAccessor, idProperty); }
@Nullable @SuppressWarnings("unchecked") public <T> T getPropertyValue(MongoPersistentProperty property) { if (property.isDbReference() && property.getDBRef().lazy()) { Object rawRefValue = accessor.get(property); if (rawRefValue == null) { return null; } DbRefResolverCallback callback = new DefaultDbRefResolverCallback(accessor.getDocument(), path, evaluator, MappingMongoConverter.this); DBRef dbref = rawRefValue instanceof DBRef ? (DBRef) rawRefValue : null; return (T) dbRefResolver.resolveDbRef(property, dbref, callback, dbRefProxyHandler); } return super.getPropertyValue(property); } }
/** * Returns the value the given {@link MongoPersistentProperty} refers to. By default this will be a direct field but * the method will also transparently resolve nested values the {@link MongoPersistentProperty} might refer to through * a path expression in the field name metadata. * * @param property must not be {@literal null}. * @return */ @Nullable public Object get(MongoPersistentProperty property) { String fieldName = property.getFieldName(); Map<String, Object> map = BsonUtils.asMap(document); if (!fieldName.contains(".")) { return map.get(fieldName); } Iterator<String> parts = Arrays.asList(fieldName.split("\\.")).iterator(); Map<String, Object> source = map; Object result = null; while (source != null && parts.hasNext()) { result = source.get(parts.next()); if (parts.hasNext()) { source = getAsMap(result); } } return result; }
private void writeSimpleInternal(Object value, Bson bson, MongoPersistentProperty property) { DocumentAccessor accessor = new DocumentAccessor(bson); accessor.put(property, getPotentiallyConvertedSimpleWrite(value)); }
accessor.put(prop, collectionInternal); return; accessor.put(prop, mapDbObj); return; accessor.put(prop, dbRefObj); return; accessor.put(prop, conversionService.convert(obj, basicTargetType.get())); return; : mappingContext.getRequiredPersistentEntity(type); Object existingValue = accessor.get(prop); Document document = existingValue instanceof Document ? (Document) existingValue : new Document(); accessor.put(prop, document);
/** * Returns the raw identifier for the given {@link MongoPersistentEntity} or the value of the default identifier * field. * * @param entity must not be {@literal null}. * @return */ public Object getRawId(MongoPersistentEntity<?> entity) { return entity.hasIdProperty() ? get(entity.getRequiredIdProperty()) : BsonUtils.asMap(document).get("_id"); }
/** * Creates a new {@link MongoDbPropertyValueProvider} for the given source, {@link SpELExpressionEvaluator} and * {@link ObjectPath}. * * @param source must not be {@literal null}. * @param evaluator must not be {@literal null}. * @param path must not be {@literal null}. */ MongoDbPropertyValueProvider(Bson source, SpELExpressionEvaluator evaluator, ObjectPath path) { this(new DocumentAccessor(source), evaluator, path); }
private DbRefResolverCallback getDbRefResolverCallback(DocumentAccessor documentAccessor, ObjectPath currentPath, SpELExpressionEvaluator evaluator) { return new DefaultDbRefResolverCallback(documentAccessor.getDocument(), currentPath, evaluator, MappingMongoConverter.this); }
/** * Reads the identifier from either the bean backing the {@link PersistentPropertyAccessor} or the source document in * case the identifier has not be populated yet. In this case the identifier is set on the bean for further reference. * * @param accessor must not be {@literal null}. * @param document must not be {@literal null}. * @param entity must not be {@literal null}. * @param path * @param evaluator * @return */ private Object readAndPopulateIdentifier(PersistentPropertyAccessor<?> accessor, DocumentAccessor document, MongoPersistentEntity<?> entity, ObjectPath path, SpELExpressionEvaluator evaluator) { Object rawId = document.getRawId(entity); if (!entity.hasIdProperty() || rawId == null) { return rawId; } MongoPersistentProperty idProperty = entity.getRequiredIdProperty(); if (idProperty.isImmutable() && entity.isConstructorArgument(idProperty)) { return rawId; } accessor.setProperty(idProperty, readIdValue(path, evaluator, idProperty, rawId)); return rawId; }
/** * Puts the given value into the backing {@link Document} based on the coordinates defined through the given * {@link MongoPersistentProperty}. By default this will be the plain field name. But field names might also consist * of path traversals so we might need to create intermediate {@link BasicDocument}s. * * @param prop must not be {@literal null}. * @param value */ public void put(MongoPersistentProperty prop, @Nullable Object value) { Assert.notNull(prop, "MongoPersistentProperty must not be null!"); String fieldName = prop.getFieldName(); if (!fieldName.contains(".")) { BsonUtils.addToMap(document, fieldName, value); return; } Iterator<String> parts = Arrays.asList(fieldName.split("\\.")).iterator(); Bson document = this.document; while (parts.hasNext()) { String part = parts.next(); if (parts.hasNext()) { document = getOrCreateNestedDocument(part, document); } else { BsonUtils.addToMap(document, part, value); } } }
private void readProperties(MongoPersistentEntity<?> entity, PersistentPropertyAccessor<?> accessor, DocumentAccessor documentAccessor, MongoDbPropertyValueProvider valueProvider, ObjectPath currentPath, SpELExpressionEvaluator evaluator) { DbRefResolverCallback callback = null; for (MongoPersistentProperty prop : entity) { if (prop.isAssociation() && !entity.isConstructorArgument(prop)) { if (callback == null) { callback = getDbRefResolverCallback(documentAccessor, currentPath, evaluator); } readAssociation(prop.getRequiredAssociation(), accessor, documentAccessor, dbRefProxyHandler, callback); continue; } // We skip the id property since it was already set if (entity.isIdProperty(prop)) { continue; } if (entity.isConstructorArgument(prop) || !documentAccessor.hasValue(prop)) { continue; } if (prop.isAssociation()) { if (callback == null) { callback = getDbRefResolverCallback(documentAccessor, currentPath, evaluator); } readAssociation(prop.getRequiredAssociation(), accessor, documentAccessor, dbRefProxyHandler, callback); continue; } accessor.setProperty(prop, valueProvider.getPropertyValue(prop)); } }
private void writeSimpleInternal(Object value, Bson bson, MongoPersistentProperty property) { DocumentAccessor accessor = new DocumentAccessor(bson); accessor.put(property, getPotentiallyConvertedSimpleWrite(value)); }
accessor.put(prop, collectionInternal); return; accessor.put(prop, mapDbObj); return; accessor.put(prop, dbRefObj); return; accessor.put(prop, conversionService.convert(obj, basicTargetType.get())); return; : mappingContext.getRequiredPersistentEntity(type); Object existingValue = accessor.get(prop); Document document = existingValue instanceof Document ? (Document) existingValue : new Document(); accessor.put(prop, document);
private void readAssociation(Association<MongoPersistentProperty> association, PersistentPropertyAccessor<?> accessor, DocumentAccessor documentAccessor, DbRefProxyHandler handler, DbRefResolverCallback callback) { MongoPersistentProperty property = association.getInverse(); Object value = documentAccessor.get(property); if (value == null) { return; } DBRef dbref = value instanceof DBRef ? (DBRef) value : null; accessor.setProperty(property, dbRefResolver.resolveDbRef(property, dbref, callback, handler)); }
private <S extends Object> S read(final MongoPersistentEntity<S> entity, final Document bson, final ObjectPath path) { SpELExpressionEvaluator evaluator = new DefaultSpELExpressionEvaluator(bson, spELContext); DocumentAccessor documentAccessor = new DocumentAccessor(bson); PreferredConstructor<S, MongoPersistentProperty> persistenceConstructor = entity.getPersistenceConstructor(); ParameterValueProvider<MongoPersistentProperty> provider = persistenceConstructor != null && persistenceConstructor.hasParameters() ? getParameterProvider(entity, documentAccessor, evaluator, path) : NoOpParameterValueProvider.INSTANCE; EntityInstantiator instantiator = instantiators.getInstantiatorFor(entity); S instance = instantiator.createInstance(entity, provider); if (entity.requiresPropertyPopulation()) { return populateProperties(entity, documentAccessor, path, evaluator, instance); } return instance; }
private DbRefResolverCallback getDbRefResolverCallback(DocumentAccessor documentAccessor, ObjectPath currentPath, SpELExpressionEvaluator evaluator) { return new DefaultDbRefResolverCallback(documentAccessor.getDocument(), currentPath, evaluator, MappingMongoConverter.this); }
/** * Reads the identifier from either the bean backing the {@link PersistentPropertyAccessor} or the source document in * case the identifier has not be populated yet. In this case the identifier is set on the bean for further reference. * * @param accessor must not be {@literal null}. * @param document must not be {@literal null}. * @param entity must not be {@literal null}. * @param path * @param evaluator * @return */ private Object readAndPopulateIdentifier(PersistentPropertyAccessor<?> accessor, DocumentAccessor document, MongoPersistentEntity<?> entity, ObjectPath path, SpELExpressionEvaluator evaluator) { Object rawId = document.getRawId(entity); if (!entity.hasIdProperty() || rawId == null) { return rawId; } MongoPersistentProperty idProperty = entity.getRequiredIdProperty(); if (idProperty.isImmutable() && entity.isConstructorArgument(idProperty)) { return rawId; } accessor.setProperty(idProperty, readIdValue(path, evaluator, idProperty, rawId)); return rawId; }
/** * Puts the given value into the backing {@link Document} based on the coordinates defined through the given * {@link MongoPersistentProperty}. By default this will be the plain field name. But field names might also consist * of path traversals so we might need to create intermediate {@link BasicDocument}s. * * @param prop must not be {@literal null}. * @param value */ public void put(MongoPersistentProperty prop, @Nullable Object value) { Assert.notNull(prop, "MongoPersistentProperty must not be null!"); String fieldName = prop.getFieldName(); if (!fieldName.contains(".")) { BsonUtils.addToMap(document, fieldName, value); return; } Iterator<String> parts = Arrays.asList(fieldName.split("\\.")).iterator(); Bson document = this.document; while (parts.hasNext()) { String part = parts.next(); if (parts.hasNext()) { document = getOrCreateNestedDocument(part, document); } else { BsonUtils.addToMap(document, part, value); } } }
private void readProperties(MongoPersistentEntity<?> entity, PersistentPropertyAccessor<?> accessor, DocumentAccessor documentAccessor, MongoDbPropertyValueProvider valueProvider, ObjectPath currentPath, SpELExpressionEvaluator evaluator) { DbRefResolverCallback callback = null; for (MongoPersistentProperty prop : entity) { if (prop.isAssociation() && !entity.isConstructorArgument(prop)) { if (callback == null) { callback = getDbRefResolverCallback(documentAccessor, currentPath, evaluator); } readAssociation(prop.getRequiredAssociation(), accessor, documentAccessor, dbRefProxyHandler, callback); continue; } // We skip the id property since it was already set if (entity.isIdProperty(prop)) { continue; } if (entity.isConstructorArgument(prop) || !documentAccessor.hasValue(prop)) { continue; } if (prop.isAssociation()) { if (callback == null) { callback = getDbRefResolverCallback(documentAccessor, currentPath, evaluator); } readAssociation(prop.getRequiredAssociation(), accessor, documentAccessor, dbRefProxyHandler, callback); continue; } accessor.setProperty(prop, valueProvider.getPropertyValue(prop)); } }
protected void writeInternal(@Nullable Object obj, Bson bson, @Nullable MongoPersistentEntity<?> entity) { if (obj == null) { return; } if (null == entity) { throw new MappingException("No mapping metadata found for entity of type " + obj.getClass().getName()); } PersistentPropertyAccessor<?> accessor = entity.getPropertyAccessor(obj); DocumentAccessor dbObjectAccessor = new DocumentAccessor(bson); MongoPersistentProperty idProperty = entity.getIdProperty(); if (idProperty != null && !dbObjectAccessor.hasValue(idProperty)) { Object value = idMapper.convertId(accessor.getProperty(idProperty)); if (value != null) { dbObjectAccessor.put(idProperty, value); } } writeProperties(bson, entity, accessor, dbObjectAccessor, idProperty); }