DATACMNS-266 - Use new common Maven build infrastructure.
Simplified project setup to be a single module build again. Using Spring Data Build parent POM to simplify project setup. See https://github.com/SpringSource/spring-data-build#spring-data-build-infrastructure
This commit is contained in:
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Copyright 2012 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Declares a field as the one representing the principal that created the entity containing the field.
|
||||
*
|
||||
* @author Ranie Jade Ramiso
|
||||
* @author Oliver Gierke
|
||||
* @since 1.5
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(value = { ElementType.FIELD, ElementType.ANNOTATION_TYPE })
|
||||
public @interface CreatedBy {
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Copyright 2012 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Declares a field as the one representing the date the entity containing the field was created.
|
||||
*
|
||||
* @author Ranie Jade Ramiso
|
||||
* @author Oliver Gierke
|
||||
* @since 1.5
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(value = { ElementType.FIELD, ElementType.ANNOTATION_TYPE })
|
||||
public @interface CreatedDate {
|
||||
}
|
||||
30
src/main/java/org/springframework/data/annotation/Id.java
Normal file
30
src/main/java/org/springframework/data/annotation/Id.java
Normal file
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Copyright (c) 2011 by the original author(s).
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.data.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* @author J. Brisbin <jbrisbin@vmware.com>
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(value = { ElementType.FIELD })
|
||||
public @interface Id {
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Copyright 2012 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Declares a field as the one representing the principal that recently modified the entity containing the field.
|
||||
*
|
||||
* @author Ranie Jade Ramiso
|
||||
* @author Oliver Gierke
|
||||
* @since 1.5
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(value = { ElementType.FIELD, ElementType.ANNOTATION_TYPE })
|
||||
public @interface LastModifiedBy {
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Copyright 2012 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Declares a field as the one representing the date the entity containing the field was recently modified.
|
||||
*
|
||||
* @author Ranie Jade Ramiso
|
||||
* @author Oliver Gierke
|
||||
* @since 1.5
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(value = { ElementType.FIELD, ElementType.ANNOTATION_TYPE })
|
||||
public @interface LastModifiedDate {
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Copyright (c) 2011 by the original author(s).
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.data.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* @author Jon Brisbin <jbrisbin@vmware.com>
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.CONSTRUCTOR)
|
||||
public @interface PersistenceConstructor {
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Copyright (c) 2011 by the original author(s).
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.data.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* @author J. Brisbin <jbrisbin@vmware.com>
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(value = { ElementType.TYPE, ElementType.ANNOTATION_TYPE, ElementType.FIELD, ElementType.PARAMETER })
|
||||
public @interface Persistent {
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright 2011-2012 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Meta-annotation to be used to annotate annotations that mark references to other objects.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
* @author Jon Brisbin
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ ElementType.ANNOTATION_TYPE, ElementType.FIELD })
|
||||
public @interface Reference {
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Copyright 20011-2012 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Marks a field to be transient for the mapping framework. Thus the property will not be persisted and not further
|
||||
* inspected by the mapping framework.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
* @author Jon Brisbin
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.FIELD)
|
||||
public @interface Transient {
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright 2011 by the original author(s).
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.annotation;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Inherited;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import org.springframework.data.mapping.PersistentEntity;
|
||||
|
||||
/**
|
||||
* Annotation to allow {@link String} based type aliases to be used when writing type information for
|
||||
* {@link PersistentEntity}s.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
@Documented
|
||||
@Inherited
|
||||
@Target({ ElementType.TYPE })
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface TypeAlias {
|
||||
|
||||
/**
|
||||
* The type alias to be used when persisting
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
String value();
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright 2012 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.annotation;
|
||||
|
||||
import static java.lang.annotation.ElementType.*;
|
||||
import static java.lang.annotation.RetentionPolicy.*;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Demarcates a property to be used as version field to implement optimistic locking on entities.
|
||||
*
|
||||
* @since 1.5
|
||||
* @author Patryk Wasik
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
@Documented
|
||||
@Target({ FIELD, ANNOTATION_TYPE })
|
||||
@Retention(RUNTIME)
|
||||
public @interface Version {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
/**
|
||||
* Core annotations being used by Spring Data.
|
||||
*/
|
||||
package org.springframework.data.annotation;
|
||||
@@ -0,0 +1,139 @@
|
||||
package org.springframework.data.auditing;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import org.joda.time.DateTime;
|
||||
import org.springframework.data.annotation.CreatedBy;
|
||||
import org.springframework.data.annotation.CreatedDate;
|
||||
import org.springframework.data.annotation.LastModifiedBy;
|
||||
import org.springframework.data.annotation.LastModifiedDate;
|
||||
import org.springframework.data.util.ReflectionUtils;
|
||||
import org.springframework.data.util.ReflectionUtils.AnnotationFieldFilter;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Inspects the given {@link Class} for fields annotated by {@link CreatedBy}, {@link CreatedDate},
|
||||
* {@link LastModifiedBy} , and {@link LastModifiedDate}. Only one field per annotation is stored.
|
||||
*
|
||||
* @author Ranie Jade Ramiso
|
||||
* @author Oliver Gierke
|
||||
* @since 1.5
|
||||
*/
|
||||
class AnnotationAuditingMetadata {
|
||||
|
||||
private static final AnnotationFieldFilter CREATED_BY_FILTER = new AnnotationFieldFilter(CreatedBy.class);
|
||||
private static final AnnotationFieldFilter CREATED_DATE_FILTER = new AnnotationFieldFilter(CreatedDate.class);
|
||||
private static final AnnotationFieldFilter LAST_MODIFIED_BY_FILTER = new AnnotationFieldFilter(LastModifiedBy.class);
|
||||
private static final AnnotationFieldFilter LAST_MODIFIED_DATE_FILTER = new AnnotationFieldFilter(
|
||||
LastModifiedDate.class);
|
||||
|
||||
private static final Map<Class<?>, AnnotationAuditingMetadata> METADATA_CACHE = new ConcurrentHashMap<Class<?>, AnnotationAuditingMetadata>();
|
||||
|
||||
static final List<Class<?>> SUPPORTED_DATE_TYPES;
|
||||
|
||||
static {
|
||||
|
||||
List<Class<?>> types = new ArrayList<Class<?>>(4);
|
||||
types.add(DateTime.class);
|
||||
types.add(Date.class);
|
||||
types.add(Long.class);
|
||||
types.add(long.class);
|
||||
|
||||
SUPPORTED_DATE_TYPES = Collections.unmodifiableList(types);
|
||||
}
|
||||
|
||||
private final Field createdByField;
|
||||
private final Field createdDateField;
|
||||
private final Field lastModifiedByField;
|
||||
private final Field lastModifiedDateField;
|
||||
|
||||
private AnnotationAuditingMetadata(Class<?> type) {
|
||||
|
||||
Assert.notNull(type, "Given type must not be null!");
|
||||
|
||||
this.createdByField = ReflectionUtils.findField(type, CREATED_BY_FILTER);
|
||||
this.createdDateField = ReflectionUtils.findField(type, CREATED_DATE_FILTER);
|
||||
this.lastModifiedByField = ReflectionUtils.findField(type, LAST_MODIFIED_BY_FILTER);
|
||||
this.lastModifiedDateField = ReflectionUtils.findField(type, LAST_MODIFIED_DATE_FILTER);
|
||||
|
||||
assertValidDateFieldType(createdDateField);
|
||||
assertValidDateFieldType(lastModifiedDateField);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the given field has a type that is a supported date type.
|
||||
*
|
||||
* @param field
|
||||
*/
|
||||
private void assertValidDateFieldType(Field field) {
|
||||
|
||||
if (field == null || SUPPORTED_DATE_TYPES.contains(field.getType())) {
|
||||
return;
|
||||
}
|
||||
|
||||
throw new IllegalStateException(String.format(
|
||||
"Found created/modified date field with type %s but only %s are supported!", field.getType(),
|
||||
SUPPORTED_DATE_TYPES));
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a {@link AnnotationAuditingMetadata} for the given {@link Class}.
|
||||
*
|
||||
* @param type the type to inspect, must not be {@literal null}.
|
||||
*/
|
||||
public static AnnotationAuditingMetadata getMetadata(Class<?> type) {
|
||||
|
||||
if (METADATA_CACHE.containsKey(type)) {
|
||||
return METADATA_CACHE.get(type);
|
||||
}
|
||||
|
||||
AnnotationAuditingMetadata metadata = new AnnotationAuditingMetadata(type);
|
||||
METADATA_CACHE.put(type, metadata);
|
||||
return metadata;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the {@link Class} represented in this instance is auditable or not.
|
||||
*/
|
||||
public boolean isAuditable() {
|
||||
if (createdByField == null && createdDateField == null && lastModifiedByField == null
|
||||
&& lastModifiedDateField == null) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the field annotated by {@link CreatedBy}, or {@literal null}.
|
||||
*/
|
||||
public Field getCreatedByField() {
|
||||
return createdByField;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the field annotated by {@link CreatedDate}, or {@literal null}.
|
||||
*/
|
||||
public Field getCreatedDateField() {
|
||||
return createdDateField;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the field annotated by {@link LastModifiedBy}, or {@literal null}.
|
||||
*/
|
||||
public Field getLastModifiedByField() {
|
||||
return lastModifiedByField;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the field annotated by {@link LastModifiedDate}, or {@literal null}.
|
||||
*/
|
||||
public Field getLastModifiedDateField() {
|
||||
return lastModifiedDateField;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* Copyright 2012 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.auditing;
|
||||
|
||||
import org.joda.time.DateTime;
|
||||
|
||||
/**
|
||||
* Interface to abstract the ways setting the auditing information can be implemented.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
* @since 1.5
|
||||
*/
|
||||
public interface AuditableBeanWrapper {
|
||||
|
||||
/**
|
||||
* Set the creator of the object.
|
||||
*
|
||||
* @param value
|
||||
*/
|
||||
void setCreatedBy(Object value);
|
||||
|
||||
/**
|
||||
* Set the date the object was created.
|
||||
*
|
||||
* @param value
|
||||
*/
|
||||
void setCreatedDate(DateTime value);
|
||||
|
||||
/**
|
||||
* Set the last modifier of the object.
|
||||
*
|
||||
* @param value
|
||||
*/
|
||||
void setLastModifiedBy(Object value);
|
||||
|
||||
/**
|
||||
* Set the last modification date.
|
||||
*
|
||||
* @param value
|
||||
*/
|
||||
void setLastModifiedDate(DateTime value);
|
||||
}
|
||||
@@ -0,0 +1,220 @@
|
||||
/*
|
||||
* Copyright 2012 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.auditing;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.Date;
|
||||
|
||||
import org.joda.time.DateTime;
|
||||
import org.springframework.data.domain.Auditable;
|
||||
import org.springframework.data.util.ReflectionUtils;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* A factory class to {@link AuditableBeanWrapper} instances.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
* @since 1.5
|
||||
*/
|
||||
class AuditableBeanWrapperFactory {
|
||||
|
||||
/**
|
||||
* Returns an {@link AuditableBeanWrapper} if the given object is capable of being equipped with auditing information.
|
||||
*
|
||||
* @param source the auditing candidate.
|
||||
* @return
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public AuditableBeanWrapper getBeanWrapperFor(Object source) {
|
||||
|
||||
if (source == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (source instanceof Auditable) {
|
||||
return new AuditableInterfaceBeanWrapper((Auditable<Object, ?>) source);
|
||||
}
|
||||
|
||||
AnnotationAuditingMetadata metadata = AnnotationAuditingMetadata.getMetadata(source.getClass());
|
||||
|
||||
if (metadata.isAuditable()) {
|
||||
return new ReflectionAuditingBeanWrapper(source);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* An {@link AuditableBeanWrapper} that works with objects implementing
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
static class AuditableInterfaceBeanWrapper implements AuditableBeanWrapper {
|
||||
|
||||
private final Auditable<Object, ?> auditable;
|
||||
|
||||
public AuditableInterfaceBeanWrapper(Auditable<Object, ?> auditable) {
|
||||
this.auditable = auditable;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.auditing.AuditableBeanWrapper#setCreatedBy(java.lang.Object)
|
||||
*/
|
||||
public void setCreatedBy(Object value) {
|
||||
auditable.setCreatedBy(value);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.auditing.AuditableBeanWrapper#setCreatedDate(org.joda.time.DateTime)
|
||||
*/
|
||||
public void setCreatedDate(DateTime value) {
|
||||
auditable.setCreatedDate(value);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.auditing.AuditableBeanWrapper#setLastModifiedBy(java.lang.Object)
|
||||
*/
|
||||
public void setLastModifiedBy(Object value) {
|
||||
auditable.setLastModifiedBy(value);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.auditing.AuditableBeanWrapper#setLastModifiedDate(org.joda.time.DateTime)
|
||||
*/
|
||||
public void setLastModifiedDate(DateTime value) {
|
||||
auditable.setLastModifiedDate(value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An {@link AuditableBeanWrapper} implementation that sets values on the target object using refelction.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
static class ReflectionAuditingBeanWrapper implements AuditableBeanWrapper {
|
||||
|
||||
private final AnnotationAuditingMetadata metadata;
|
||||
private final Object target;
|
||||
|
||||
/**
|
||||
* Creates a new {@link ReflectionAuditingBeanWrapper} to set auditing data on the given target object.
|
||||
*
|
||||
* @param target must not be {@literal null}.
|
||||
*/
|
||||
public ReflectionAuditingBeanWrapper(Object target) {
|
||||
|
||||
Assert.notNull(target, "Target object must not be null!");
|
||||
|
||||
this.metadata = AnnotationAuditingMetadata.getMetadata(target.getClass());
|
||||
this.target = target;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.auditing.AuditableBeanWrapper#setCreatedBy(java.lang.Object)
|
||||
*/
|
||||
public void setCreatedBy(Object value) {
|
||||
setField(metadata.getCreatedByField(), value);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.auditing.AuditableBeanWrapper#setCreatedDate(org.joda.time.DateTime)
|
||||
*/
|
||||
public void setCreatedDate(DateTime value) {
|
||||
setDateField(metadata.getCreatedDateField(), value);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.auditing.AuditableBeanWrapper#setLastModifiedBy(java.lang.Object)
|
||||
*/
|
||||
public void setLastModifiedBy(Object value) {
|
||||
setField(metadata.getLastModifiedByField(), value);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.auditing.AuditableBeanWrapper#setLastModifiedDate(org.joda.time.DateTime)
|
||||
*/
|
||||
public void setLastModifiedDate(DateTime value) {
|
||||
setDateField(metadata.getLastModifiedDateField(), value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the given field to the given value if the field is not {@literal null}.
|
||||
*
|
||||
* @param field
|
||||
* @param value
|
||||
*/
|
||||
private void setField(Field field, Object value) {
|
||||
|
||||
if (field != null) {
|
||||
ReflectionUtils.setField(field, target, value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the given field to the given value if the field is not {@literal null}.
|
||||
*
|
||||
* @param field
|
||||
* @param value
|
||||
*/
|
||||
private void setDateField(Field field, DateTime value) {
|
||||
|
||||
if (field == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
ReflectionUtils.setField(field, target, getDateValueToSet(value, field));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link DateTime} in a type compatible to the given field.
|
||||
*
|
||||
* @param value
|
||||
* @param field must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
private Object getDateValueToSet(DateTime value, Field field) {
|
||||
|
||||
if (value == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
Class<?> targetType = field.getType();
|
||||
|
||||
if (DateTime.class.equals(targetType)) {
|
||||
return value;
|
||||
}
|
||||
|
||||
if (Date.class.equals(targetType)) {
|
||||
return value.toDate();
|
||||
}
|
||||
|
||||
if (Long.class.equals(targetType) || long.class.equals(targetType)) {
|
||||
return value.getMillis();
|
||||
}
|
||||
|
||||
throw new IllegalArgumentException(String.format("Invalid date type for field %s! Supported types are %s.",
|
||||
field, AnnotationAuditingMetadata.SUPPORTED_DATE_TYPES));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,174 @@
|
||||
/*
|
||||
* Copyright 2012 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.auditing;
|
||||
|
||||
import org.joda.time.DateTime;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.data.domain.Auditable;
|
||||
import org.springframework.data.domain.AuditorAware;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Auditing handler to mark entity objects created and modified.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
* @since 1.5
|
||||
*/
|
||||
public class AuditingHandler<T> implements InitializingBean {
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(AuditingHandler.class);
|
||||
|
||||
private final AuditableBeanWrapperFactory factory = new AuditableBeanWrapperFactory();
|
||||
private DateTimeProvider dateTimeProvider = CurrentDateTimeProvider.INSTANCE;
|
||||
private AuditorAware<T> auditorAware;
|
||||
private boolean dateTimeForNow = true;
|
||||
private boolean modifyOnCreation = true;
|
||||
|
||||
/**
|
||||
* Setter to inject a {@code AuditorAware} component to retrieve the current auditor.
|
||||
*
|
||||
* @param auditorAware the auditorAware to set
|
||||
*/
|
||||
public void setAuditorAware(final AuditorAware<T> auditorAware) {
|
||||
|
||||
Assert.notNull(auditorAware);
|
||||
this.auditorAware = auditorAware;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter do determine if {@link Auditable#setCreatedDate(DateTime)} and
|
||||
* {@link Auditable#setLastModifiedDate(DateTime)} shall be filled with the current Java time. Defaults to
|
||||
* {@code true}. One might set this to {@code false} to use database features to set entity time.
|
||||
*
|
||||
* @param dateTimeForNow the dateTimeForNow to set
|
||||
*/
|
||||
public void setDateTimeForNow(boolean dateTimeForNow) {
|
||||
this.dateTimeForNow = dateTimeForNow;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set this to false if you want to treat entity creation as modification and thus set the current date as
|
||||
* modification date, too. Defaults to {@code true}.
|
||||
*
|
||||
* @param modifyOnCreation if modification information shall be set on creation, too
|
||||
*/
|
||||
public void setModifyOnCreation(boolean modifyOnCreation) {
|
||||
this.modifyOnCreation = modifyOnCreation;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the {@link DateTimeProvider} to be used to determine the dates to be set.
|
||||
*
|
||||
* @param dateTimeProvider
|
||||
*/
|
||||
public void setDateTimeProvider(DateTimeProvider dateTimeProvider) {
|
||||
this.dateTimeProvider = dateTimeProvider == null ? CurrentDateTimeProvider.INSTANCE : dateTimeProvider;
|
||||
}
|
||||
|
||||
/**
|
||||
* Marks the given object as created.
|
||||
*
|
||||
* @param source
|
||||
*/
|
||||
public void markCreated(Object source) {
|
||||
touch(source, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Marks the given object as modified.
|
||||
*
|
||||
* @param source
|
||||
*/
|
||||
public void markModified(Object source) {
|
||||
touch(source, false);
|
||||
}
|
||||
|
||||
private void touch(Object target, boolean isNew) {
|
||||
|
||||
AuditableBeanWrapper wrapper = factory.getBeanWrapperFor(target);
|
||||
|
||||
if (wrapper == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
T auditor = touchAuditor(wrapper, isNew);
|
||||
DateTime now = dateTimeForNow ? touchDate(wrapper, isNew) : null;
|
||||
|
||||
Object defaultedNow = now == null ? "not set" : now;
|
||||
Object defaultedAuditor = auditor == null ? "unknown" : auditor;
|
||||
|
||||
LOGGER.debug("Touched {} - Last modification at {} by {}", new Object[] { target, defaultedNow, defaultedAuditor });
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets modifying and creating auditioner. Creating auditioner is only set on new auditables.
|
||||
*
|
||||
* @param auditable
|
||||
* @return
|
||||
*/
|
||||
private T touchAuditor(AuditableBeanWrapper wrapper, boolean isNew) {
|
||||
|
||||
if (null == auditorAware) {
|
||||
return null;
|
||||
}
|
||||
|
||||
T auditor = auditorAware.getCurrentAuditor();
|
||||
|
||||
if (isNew) {
|
||||
wrapper.setCreatedBy(auditor);
|
||||
if (!modifyOnCreation) {
|
||||
return auditor;
|
||||
}
|
||||
}
|
||||
|
||||
wrapper.setLastModifiedBy(auditor);
|
||||
return auditor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Touches the auditable regarding modification and creation date. Creation date is only set on new auditables.
|
||||
*
|
||||
* @param wrapper
|
||||
* @return
|
||||
*/
|
||||
private DateTime touchDate(AuditableBeanWrapper wrapper, boolean isNew) {
|
||||
|
||||
DateTime now = dateTimeProvider.getDateTime();
|
||||
|
||||
if (isNew) {
|
||||
wrapper.setCreatedDate(now);
|
||||
if (!modifyOnCreation) {
|
||||
return now;
|
||||
}
|
||||
}
|
||||
|
||||
wrapper.setLastModifiedDate(now);
|
||||
return now;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet()
|
||||
*/
|
||||
public void afterPropertiesSet() {
|
||||
|
||||
if (auditorAware == null) {
|
||||
LOGGER.debug("No AuditorAware set! Auditing will not be applied!");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright 2012 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.auditing;
|
||||
|
||||
import org.joda.time.DateTime;
|
||||
|
||||
/**
|
||||
* Default {@link DateTimeProvider} simply creating new {@link DateTime} instances for each method call.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
* @since 1.5
|
||||
*/
|
||||
public enum CurrentDateTimeProvider implements DateTimeProvider {
|
||||
|
||||
INSTANCE;
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.jpa.domain.support.DateTimeProvider#getDateTime()
|
||||
*/
|
||||
public DateTime getDateTime() {
|
||||
return new DateTime();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright 2012 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.auditing;
|
||||
|
||||
import org.joda.time.DateTime;
|
||||
|
||||
/**
|
||||
* SPI to calculate the {@link DateTime} instance to be used when auditing.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
* @since 1.5
|
||||
*/
|
||||
public interface DateTimeProvider {
|
||||
|
||||
/**
|
||||
* Returns the {@link DateTime} to be used as modification date.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
DateTime getDateTime();
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
* Copyright 2012 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.auditing;
|
||||
|
||||
import org.springframework.data.support.IsNewStrategy;
|
||||
import org.springframework.data.support.IsNewStrategyFactory;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* {@link AuditingHandler} extension that uses an {@link IsNewStrategyFactory} to expose a generic
|
||||
* {@link #markAudited(Object)} method that will route calls to {@link #markCreated(Object)} or
|
||||
* {@link #markModified(Object)} based on the {@link IsNewStrategy} determined from the factory.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
* @since 1.5
|
||||
*/
|
||||
public class IsNewAwareAuditingHandler<T> extends AuditingHandler<T> {
|
||||
|
||||
private final IsNewStrategyFactory isNewStrategyFactory;
|
||||
|
||||
/**
|
||||
* Creates a new {@link IsNewAwareAuditingHandler} using the given {@link IsNewStrategyFactory}.
|
||||
*
|
||||
* @param isNewStrategyFactory must not be {@literal null}.
|
||||
*/
|
||||
public IsNewAwareAuditingHandler(IsNewStrategyFactory isNewStrategyFactory) {
|
||||
|
||||
Assert.notNull(isNewStrategyFactory, "IsNewStrategy must not be null!");
|
||||
this.isNewStrategyFactory = isNewStrategyFactory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Marks the given object created or modified based on the {@link IsNewStrategy} returned by the
|
||||
* {@link IsNewStrategyFactory} configured. Will rout the calls to {@link #markCreated(Object)} and
|
||||
* {@link #markModified(Object)} accordingly.
|
||||
*
|
||||
* @param object
|
||||
*/
|
||||
public void markAudited(Object object) {
|
||||
|
||||
if (object == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
IsNewStrategy strategy = isNewStrategyFactory.getIsNewStrategy(object.getClass());
|
||||
|
||||
if (strategy.isNew(object)) {
|
||||
markCreated(object);
|
||||
} else {
|
||||
markModified(object);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,117 @@
|
||||
/*
|
||||
* Copyright 2011-2012 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.authentication;
|
||||
|
||||
import org.springframework.util.ObjectUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Class used to provide credentials for username/password authentication
|
||||
*
|
||||
* @author Thomas Risberg
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public class UserCredentials {
|
||||
|
||||
public static final UserCredentials NO_CREDENTIALS = new UserCredentials(null, null);
|
||||
|
||||
private final String username;
|
||||
private final String password;
|
||||
|
||||
/**
|
||||
* Creates a new {@link UserCredentials} instance from the given username and password. Empty {@link String}s provided
|
||||
* will be treated like no username or password set.
|
||||
*
|
||||
* @param username
|
||||
* @param password
|
||||
*/
|
||||
public UserCredentials(String username, String password) {
|
||||
this.username = StringUtils.hasText(username) ? username : null;
|
||||
this.password = StringUtils.hasText(password) ? password : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the username to use for authentication.
|
||||
*
|
||||
* @return the username
|
||||
*/
|
||||
public String getUsername() {
|
||||
return username;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the password to use for authentication.
|
||||
*
|
||||
* @return the password
|
||||
*/
|
||||
public String getPassword() {
|
||||
return password;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the credentials contain a username.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public boolean hasUsername() {
|
||||
return this.username != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the credentials contain a password.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public boolean hasPassword() {
|
||||
return this.password != null;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see java.lang.Object#equals(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
|
||||
if (obj == this) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (obj == null || !getClass().equals(obj.getClass())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
UserCredentials that = (UserCredentials) obj;
|
||||
|
||||
return ObjectUtils.nullSafeEquals(this.username, that.username)
|
||||
&& ObjectUtils.nullSafeEquals(this.password, that.password);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see java.lang.Object#hashCode()
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
|
||||
int result = 17;
|
||||
|
||||
result += 31 * ObjectUtils.nullSafeHashCode(username);
|
||||
result += 31 * ObjectUtils.nullSafeHashCode(password);
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
/**
|
||||
* Types to abstract authentication concepts.
|
||||
*/
|
||||
package org.springframework.data.authentication;
|
||||
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
* Copyright 2012 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.config;
|
||||
|
||||
import static org.springframework.beans.factory.support.BeanDefinitionBuilder.*;
|
||||
|
||||
import org.springframework.aop.framework.ProxyFactoryBean;
|
||||
import org.springframework.aop.target.LazyInitTargetSource;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||
import org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser;
|
||||
import org.springframework.beans.factory.xml.BeanDefinitionParser;
|
||||
import org.springframework.data.auditing.AuditingHandler;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
/**
|
||||
* {@link BeanDefinitionParser} that parses an {@link AuditingHandler} {@link BeanDefinition}
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
* @since 1.5
|
||||
*/
|
||||
public class AuditingHandlerBeanDefinitionParser extends AbstractSingleBeanDefinitionParser {
|
||||
|
||||
private static final String AUDITOR_AWARE_REF = "auditor-aware-ref";
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser#getBeanClass(org.w3c.dom.Element)
|
||||
*/
|
||||
@Override
|
||||
protected Class<?> getBeanClass(Element element) {
|
||||
return AuditingHandler.class;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.beans.factory.xml.AbstractBeanDefinitionParser#shouldGenerateId()
|
||||
*/
|
||||
@Override
|
||||
protected boolean shouldGenerateId() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser#doParse(org.w3c.dom.Element, org.springframework.beans.factory.support.BeanDefinitionBuilder)
|
||||
*/
|
||||
@Override
|
||||
protected void doParse(Element element, BeanDefinitionBuilder builder) {
|
||||
|
||||
String auditorAwareRef = element.getAttribute(AUDITOR_AWARE_REF);
|
||||
if (StringUtils.hasText(auditorAwareRef)) {
|
||||
builder.addPropertyValue("auditorAware", createLazyInitTargetSourceBeanDefinition(auditorAwareRef));
|
||||
}
|
||||
|
||||
ParsingUtils.setPropertyValue(builder, element, "set-dates", "dateTimeForNow");
|
||||
ParsingUtils.setPropertyReference(builder, element, "date-time-provider-ref", "dateTimeProvider");
|
||||
|
||||
}
|
||||
|
||||
private BeanDefinition createLazyInitTargetSourceBeanDefinition(String auditorAwareRef) {
|
||||
|
||||
BeanDefinitionBuilder targetSourceBuilder = rootBeanDefinition(LazyInitTargetSource.class);
|
||||
targetSourceBuilder.addPropertyValue("targetBeanName", auditorAwareRef);
|
||||
|
||||
BeanDefinitionBuilder builder = rootBeanDefinition(ProxyFactoryBean.class);
|
||||
builder.addPropertyValue("targetSource", targetSourceBuilder.getBeanDefinition());
|
||||
|
||||
return builder.getBeanDefinition();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,115 @@
|
||||
/*
|
||||
* Copyright 2012 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.config;
|
||||
|
||||
import org.springframework.beans.factory.parsing.BeanComponentDefinition;
|
||||
import org.springframework.beans.factory.support.AbstractBeanDefinition;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionReaderUtils;
|
||||
import org.springframework.beans.factory.xml.ParserContext;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
/**
|
||||
* Helper to create {@link BeanComponentDefinition} more easily.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public class BeanComponentDefinitionBuilder {
|
||||
|
||||
private final Element defaultSource;
|
||||
private final ParserContext context;
|
||||
|
||||
/**
|
||||
* Creates a new {@link BeanComponentDefinitionBuilder} using the given {@link Element} as default source and the
|
||||
* given {@link ParserContext}.
|
||||
*
|
||||
* @param defaultSource must not be {@literal null}.
|
||||
* @param context must not be {@literal null}.
|
||||
*/
|
||||
public BeanComponentDefinitionBuilder(Element defaultSource, ParserContext context) {
|
||||
|
||||
Assert.notNull(defaultSource);
|
||||
Assert.notNull(context);
|
||||
|
||||
this.defaultSource = defaultSource;
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@link BeanComponentDefinition} from the given {@link BeanDefinitionBuilder}. Will generate a bean name.
|
||||
*
|
||||
* @param builder must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public BeanComponentDefinition getComponent(BeanDefinitionBuilder builder) {
|
||||
|
||||
Assert.notNull(builder);
|
||||
|
||||
AbstractBeanDefinition definition = builder.getRawBeanDefinition();
|
||||
String name = BeanDefinitionReaderUtils.generateBeanName(definition, context.getRegistry(), context.isNested());
|
||||
|
||||
return getComponent(builder, name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@link BeanComponentDefinition} from the given {@link BeanDefinitionBuilder} and inspects the backing
|
||||
* {@link Element}s id attribute for a name. It will use this one if found or the given fallback if not.
|
||||
*
|
||||
* @param builder must not be {@literal null}.
|
||||
* @param fallback must not be {@literal null} or empty.
|
||||
* @return
|
||||
*/
|
||||
public BeanComponentDefinition getComponentIdButFallback(BeanDefinitionBuilder builder, String fallback) {
|
||||
|
||||
Assert.hasText(fallback);
|
||||
|
||||
String id = defaultSource.getAttribute("id");
|
||||
return getComponent(builder, StringUtils.hasText(id) ? id : fallback);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@link BeanComponentDefinition} from the given {@link BeanDefinitionBuilder} using the given name.
|
||||
*
|
||||
* @param builder must not be {@literal null}.
|
||||
* @param name must not be {@literal null} or empty.
|
||||
* @return
|
||||
*/
|
||||
public BeanComponentDefinition getComponent(BeanDefinitionBuilder builder, String name) {
|
||||
return getComponent(builder, name, defaultSource);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link BeanComponentDefinition} from the given {@link BeanDefinitionBuilder} using the given name and
|
||||
* raw source object.
|
||||
*
|
||||
* @param builder must not be {@literal null}.
|
||||
* @param name must not be {@literal null}.
|
||||
* @param rawSource
|
||||
* @return
|
||||
*/
|
||||
public BeanComponentDefinition getComponent(BeanDefinitionBuilder builder, String name, Object rawSource) {
|
||||
|
||||
Assert.notNull(builder);
|
||||
Assert.hasText(name);
|
||||
|
||||
AbstractBeanDefinition definition = builder.getRawBeanDefinition();
|
||||
definition.setSource(context.extractSource(rawSource));
|
||||
|
||||
return new BeanComponentDefinition(definition, name);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* Copyright 2012 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.config;
|
||||
|
||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||
import org.springframework.data.auditing.IsNewAwareAuditingHandler;
|
||||
import org.springframework.util.Assert;
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
/**
|
||||
* {@link AuditingHandlerBeanDefinitionParser} that will register am {@link IsNewAwareAuditingHandler}. Needs to get the
|
||||
* bean id of the
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public class IsNewAwareAuditingHandlerBeanDefinitionParser extends AuditingHandlerBeanDefinitionParser {
|
||||
|
||||
private final String isNewStrategyFactoryBeanId;
|
||||
|
||||
/**
|
||||
* Creates a new {@link IsNewAwareAuditingHandlerBeanDefinitionParser}.
|
||||
*
|
||||
* @param isNewStrategyFactoryBeanId must not be {@literal null} or empty.
|
||||
*/
|
||||
public IsNewAwareAuditingHandlerBeanDefinitionParser(String isNewStrategyFactoryBeanId) {
|
||||
|
||||
Assert.hasText(isNewStrategyFactoryBeanId);
|
||||
this.isNewStrategyFactoryBeanId = isNewStrategyFactoryBeanId;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.config.AuditingHandlerBeanDefinitionParser#getBeanClass(org.w3c.dom.Element)
|
||||
*/
|
||||
@Override
|
||||
protected Class<?> getBeanClass(Element element) {
|
||||
return IsNewAwareAuditingHandler.class;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.config.AuditingHandlerBeanDefinitionParser#doParse(org.w3c.dom.Element, org.springframework.beans.factory.support.BeanDefinitionBuilder)
|
||||
*/
|
||||
@Override
|
||||
protected void doParse(Element element, BeanDefinitionBuilder builder) {
|
||||
|
||||
builder.addConstructorArgReference(isNewStrategyFactoryBeanId);
|
||||
|
||||
super.doParse(element, builder);
|
||||
}
|
||||
}
|
||||
130
src/main/java/org/springframework/data/config/ParsingUtils.java
Normal file
130
src/main/java/org/springframework/data/config/ParsingUtils.java
Normal file
@@ -0,0 +1,130 @@
|
||||
/*
|
||||
* Copyright 2011-2012 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.config;
|
||||
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.support.AbstractBeanDefinition;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||
import org.springframework.beans.factory.xml.BeanDefinitionParser;
|
||||
import org.springframework.beans.factory.xml.ParserContext;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
/**
|
||||
* Utility methods for {@link BeanDefinitionParser} implementations.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public abstract class ParsingUtils {
|
||||
|
||||
private ParsingUtils() {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures a property value for the given property name reading the attribute of the given name from the given
|
||||
* {@link Element} if the attribute is configured.
|
||||
*
|
||||
* @param builder must not be {@literal null}.
|
||||
* @param element must not be {@literal null}.
|
||||
* @param attrName must not be {@literal null} or empty.
|
||||
* @param propertyName must not be {@literal null} or empty.
|
||||
*/
|
||||
public static void setPropertyValue(BeanDefinitionBuilder builder, Element element, String attrName,
|
||||
String propertyName) {
|
||||
|
||||
Assert.notNull(builder, "BeanDefinitionBuilder must not be null!");
|
||||
Assert.notNull(element, "Element must not be null!");
|
||||
Assert.hasText(attrName, "Attribute name must not be null!");
|
||||
Assert.hasText(propertyName, "Property name must not be null!");
|
||||
|
||||
String attr = element.getAttribute(attrName);
|
||||
|
||||
if (StringUtils.hasText(attr)) {
|
||||
builder.addPropertyValue(propertyName, attr);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the property with the given attribute name on the given {@link BeanDefinitionBuilder} to the value of the
|
||||
* attribute with the given name if the attribute is configured.
|
||||
*
|
||||
* @param builder must not be {@literal null}.
|
||||
* @param element must not be {@literal null}.
|
||||
* @param attribute must not be {@literal null} or empty.
|
||||
*/
|
||||
public static void setPropertyValue(BeanDefinitionBuilder builder, Element element, String attribute) {
|
||||
setPropertyValue(builder, element, attribute, attribute);
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures a bean property reference with the value of the attribute of the given name if it is configured.
|
||||
*
|
||||
* @param builder must not be {@literal null}.
|
||||
* @param element must not be {@literal null}.
|
||||
* @param attribute must not be {@literal null} or empty.
|
||||
* @param property must not be {@literal null}or empty.
|
||||
*/
|
||||
public static void setPropertyReference(BeanDefinitionBuilder builder, Element element, String attribute,
|
||||
String property) {
|
||||
|
||||
Assert.notNull(builder, "BeanDefinitionBuilder must not be null!");
|
||||
Assert.notNull(element, "Element must not be null!");
|
||||
Assert.hasText(attribute, "Attribute name must not be null!");
|
||||
Assert.hasText(property, "Property name must not be null!");
|
||||
|
||||
String value = element.getAttribute(attribute);
|
||||
|
||||
if (StringUtils.hasText(value)) {
|
||||
builder.addPropertyReference(property, value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link BeanDefinition} built by the given {@link BeanDefinitionBuilder} enriched with source
|
||||
* information derived from the given {@link Element}.
|
||||
*
|
||||
* @param builder must not be {@literal null}.
|
||||
* @param context must not be {@literal null}.
|
||||
* @param element must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public static AbstractBeanDefinition getSourceBeanDefinition(BeanDefinitionBuilder builder, ParserContext context,
|
||||
Element element) {
|
||||
|
||||
Assert.notNull(element, "Element must not be null!");
|
||||
Assert.notNull(context, "ParserContext must not be null!");
|
||||
|
||||
return getSourceBeanDefinition(builder, context.extractSource(element));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link AbstractBeanDefinition} built by the given builder with the given extracted source applied.
|
||||
*
|
||||
* @param builder must not be {@literal null}.
|
||||
* @param source
|
||||
* @return
|
||||
*/
|
||||
public static AbstractBeanDefinition getSourceBeanDefinition(BeanDefinitionBuilder builder, Object source) {
|
||||
|
||||
Assert.notNull(builder, "Builder must not be null!");
|
||||
|
||||
AbstractBeanDefinition definition = builder.getRawBeanDefinition();
|
||||
definition.setSource(source);
|
||||
return definition;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,239 @@
|
||||
/*
|
||||
* Copyright 2010-2012 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.config;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import org.springframework.beans.BeanUtils;
|
||||
import org.springframework.beans.FatalBeanException;
|
||||
import org.springframework.beans.factory.parsing.ReaderContext;
|
||||
import org.springframework.beans.factory.xml.XmlReaderContext;
|
||||
import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider;
|
||||
import org.springframework.core.type.filter.AnnotationTypeFilter;
|
||||
import org.springframework.core.type.filter.AspectJTypeFilter;
|
||||
import org.springframework.core.type.filter.AssignableTypeFilter;
|
||||
import org.springframework.core.type.filter.RegexPatternTypeFilter;
|
||||
import org.springframework.core.type.filter.TypeFilter;
|
||||
import org.springframework.util.Assert;
|
||||
import org.w3c.dom.Element;
|
||||
import org.w3c.dom.Node;
|
||||
import org.w3c.dom.NodeList;
|
||||
|
||||
/**
|
||||
* Parser to populate the given {@link ClassPathScanningCandidateComponentProvider} with {@link TypeFilter}s parsed from
|
||||
* the given {@link Element}'s children.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public class TypeFilterParser {
|
||||
|
||||
private static final String FILTER_TYPE_ATTRIBUTE = "type";
|
||||
private static final String FILTER_EXPRESSION_ATTRIBUTE = "expression";
|
||||
|
||||
private final ReaderContext readerContext;
|
||||
private final ClassLoader classLoader;
|
||||
|
||||
/**
|
||||
* Creates a new {@link TypeFilterParser} with the given {@link ReaderContext}.
|
||||
*
|
||||
* @param readerContext must not be {@literal null}.
|
||||
*/
|
||||
public TypeFilterParser(XmlReaderContext readerContext) {
|
||||
this(readerContext, readerContext.getResourceLoader().getClassLoader());
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor to ease testing as {@link XmlReaderContext#getBeanClassLoader()} is final and thus cannot be mocked
|
||||
* easily.
|
||||
*
|
||||
* @param readerContext must not be {@literal null}.
|
||||
* @param classLoader must not be {@literal null}.
|
||||
*/
|
||||
TypeFilterParser(ReaderContext readerContext, ClassLoader classLoader) {
|
||||
|
||||
Assert.notNull(readerContext, "ReaderContext must not be null!");
|
||||
Assert.notNull(classLoader, "ClassLoader must not be null!");
|
||||
|
||||
this.readerContext = readerContext;
|
||||
this.classLoader = classLoader;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all {@link TypeFilter} declared in nested elements of the given {@link Element}. Allows to selectively
|
||||
* retrieve including or excluding filters based on the given {@link Type}.
|
||||
*
|
||||
* @param element must not be {@literal null}.
|
||||
* @param type must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public Iterable<TypeFilter> parseTypeFilters(Element element, Type type) {
|
||||
|
||||
NodeList nodeList = element.getChildNodes();
|
||||
Collection<TypeFilter> filters = new HashSet<TypeFilter>();
|
||||
|
||||
for (int i = 0; i < nodeList.getLength(); i++) {
|
||||
|
||||
Node node = nodeList.item(i);
|
||||
Element childElement = type.getElement(node);
|
||||
|
||||
if (childElement != null) {
|
||||
|
||||
try {
|
||||
filters.add(createTypeFilter(childElement, classLoader));
|
||||
} catch (RuntimeException e) {
|
||||
readerContext.error(e.getMessage(), readerContext.extractSource(element), e.getCause());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return filters;
|
||||
}
|
||||
|
||||
/**
|
||||
* Createsa a {@link TypeFilter} instance from the given {@link Element} and {@link ClassLoader}.
|
||||
*
|
||||
* @param element must not be {@literal null}.
|
||||
* @param classLoader must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
protected TypeFilter createTypeFilter(Element element, ClassLoader classLoader) {
|
||||
|
||||
String filterType = element.getAttribute(FILTER_TYPE_ATTRIBUTE);
|
||||
String expression = element.getAttribute(FILTER_EXPRESSION_ATTRIBUTE);
|
||||
|
||||
try {
|
||||
|
||||
FilterType filter = FilterType.fromString(filterType);
|
||||
return filter.getFilter(expression, classLoader);
|
||||
|
||||
} catch (ClassNotFoundException ex) {
|
||||
throw new FatalBeanException("Type filter class not found: " + expression, ex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Enum representing all the filter types available for {@code include} and {@code exclude} elements. This acts as
|
||||
* factory for {@link TypeFilter} instances.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
* @see #getFilter(String, ClassLoader)
|
||||
*/
|
||||
private static enum FilterType {
|
||||
|
||||
ANNOTATION {
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public TypeFilter getFilter(String expression, ClassLoader classLoader) throws ClassNotFoundException {
|
||||
return new AnnotationTypeFilter((Class<Annotation>) classLoader.loadClass(expression));
|
||||
}
|
||||
},
|
||||
|
||||
ASSIGNABLE {
|
||||
@Override
|
||||
public TypeFilter getFilter(String expression, ClassLoader classLoader) throws ClassNotFoundException {
|
||||
return new AssignableTypeFilter(classLoader.loadClass(expression));
|
||||
}
|
||||
},
|
||||
|
||||
ASPECTJ {
|
||||
@Override
|
||||
public TypeFilter getFilter(String expression, ClassLoader classLoader) {
|
||||
return new AspectJTypeFilter(expression, classLoader);
|
||||
}
|
||||
},
|
||||
|
||||
REGEX {
|
||||
@Override
|
||||
public TypeFilter getFilter(String expression, ClassLoader classLoader) {
|
||||
return new RegexPatternTypeFilter(Pattern.compile(expression));
|
||||
}
|
||||
},
|
||||
|
||||
CUSTOM {
|
||||
@Override
|
||||
public TypeFilter getFilter(String expression, ClassLoader classLoader) throws ClassNotFoundException {
|
||||
|
||||
Class<?> filterClass = classLoader.loadClass(expression);
|
||||
if (!TypeFilter.class.isAssignableFrom(filterClass)) {
|
||||
throw new IllegalArgumentException("Class is not assignable to [" + TypeFilter.class.getName() + "]: "
|
||||
+ expression);
|
||||
}
|
||||
return (TypeFilter) BeanUtils.instantiateClass(filterClass);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns the {@link TypeFilter} for the given expression and {@link ClassLoader}.
|
||||
*
|
||||
* @param expression
|
||||
* @param classLoader
|
||||
* @return
|
||||
* @throws ClassNotFoundException
|
||||
*/
|
||||
abstract TypeFilter getFilter(String expression, ClassLoader classLoader) throws ClassNotFoundException;
|
||||
|
||||
/**
|
||||
* Returns the {@link FilterType} for the given type as {@link String}.
|
||||
*
|
||||
* @param typeString
|
||||
* @return
|
||||
* @throws IllegalArgumentException if no {@link FilterType} could be found for the given argument.
|
||||
*/
|
||||
static FilterType fromString(String typeString) {
|
||||
|
||||
for (FilterType filter : FilterType.values()) {
|
||||
if (filter.name().equalsIgnoreCase(typeString)) {
|
||||
return filter;
|
||||
}
|
||||
}
|
||||
|
||||
throw new IllegalArgumentException("Unsupported filter type: " + typeString);
|
||||
}
|
||||
}
|
||||
|
||||
public static enum Type {
|
||||
|
||||
INCLUDE("include-filter"), EXCLUDE("exclude-filter");
|
||||
|
||||
private String elementName;
|
||||
|
||||
private Type(String elementName) {
|
||||
this.elementName = elementName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link Element} if the given {@link Node} is an {@link Element} and it's name equals the one of the
|
||||
* type.
|
||||
*
|
||||
* @param node
|
||||
* @return
|
||||
*/
|
||||
Element getElement(Node node) {
|
||||
|
||||
if (node.getNodeType() == Node.ELEMENT_NODE) {
|
||||
String localName = node.getLocalName();
|
||||
if (elementName.equals(localName)) {
|
||||
return (Element) node;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
/*
|
||||
* Copyright 2011-12 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.convert;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import org.springframework.data.mapping.PersistentEntity;
|
||||
import org.springframework.data.mapping.context.MappingContext;
|
||||
import org.springframework.data.util.ClassTypeInformation;
|
||||
import org.springframework.data.util.TypeInformation;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* {@link TypeInformationMapper} implementation that can be either set up using a {@link MappingContext} or manually set
|
||||
* up {@link Map} of {@link String} aliases to types. If a {@link MappingContext} is used the {@link Map} will be build
|
||||
* inspecting the {@link PersistentEntity} instances for type alias information.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public class ConfigurableTypeInformationMapper implements TypeInformationMapper {
|
||||
|
||||
private final Map<TypeInformation<?>, Object> typeMap;
|
||||
|
||||
/**
|
||||
* Creates a new {@link ConfigurableTypeMapper} for the given type map.
|
||||
*
|
||||
* @param sourceTypeMap must not be {@literal null}.
|
||||
*/
|
||||
public ConfigurableTypeInformationMapper(Map<? extends Class<?>, String> sourceTypeMap) {
|
||||
|
||||
Assert.notNull(sourceTypeMap);
|
||||
this.typeMap = new HashMap<TypeInformation<?>, Object>(sourceTypeMap.size());
|
||||
|
||||
for (Entry<? extends Class<?>, String> entry : sourceTypeMap.entrySet()) {
|
||||
TypeInformation<?> key = ClassTypeInformation.from(entry.getKey());
|
||||
String value = entry.getValue();
|
||||
|
||||
if (typeMap.containsValue(value)) {
|
||||
throw new IllegalArgumentException(String.format(
|
||||
"Detected mapping ambiguity! String %s cannot be mapped to more than one type!", value));
|
||||
}
|
||||
|
||||
this.typeMap.put(key, value);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.convert.TypeInformationMapper#createAliasFor(org.springframework.data.util.TypeInformation)
|
||||
*/
|
||||
public Object createAliasFor(TypeInformation<?> type) {
|
||||
return typeMap.get(type);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.convert.TypeInformationMapper#resolveTypeFrom(java.lang.Object)
|
||||
*/
|
||||
public TypeInformation<?> resolveTypeFrom(Object alias) {
|
||||
|
||||
if (alias == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
for (Entry<TypeInformation<?>, Object> entry : typeMap.entrySet()) {
|
||||
if (entry.getValue().equals(alias)) {
|
||||
return entry.getKey();
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,184 @@
|
||||
/*
|
||||
* Copyright 2011-2013 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.convert;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.data.mapping.PersistentEntity;
|
||||
import org.springframework.data.mapping.context.MappingContext;
|
||||
import org.springframework.data.util.ClassTypeInformation;
|
||||
import org.springframework.data.util.TypeInformation;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Default implementation of {@link MongoTypeMapper} allowing configuration of the key to lookup and store type
|
||||
* information in {@link DBObject}. The key defaults to {@link #DEFAULT_TYPE_KEY}. Actual type-to-{@link String}
|
||||
* conversion and back is done in {@link #getTypeString(TypeInformation)} or {@link #getTypeInformation(String)}
|
||||
* respectively.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public class DefaultTypeMapper<S> implements TypeMapper<S> {
|
||||
|
||||
private final TypeAliasAccessor<S> accessor;
|
||||
private final List<? extends TypeInformationMapper> mappers;
|
||||
|
||||
/**
|
||||
* Creates a new {@link DefaultTypeMapper} using the given {@link TypeAliasAccessor}. It will use a
|
||||
* {@link SimpleTypeInformationMapper} to calculate type aliases.
|
||||
*
|
||||
* @param accessor must not be {@literal null}.
|
||||
*/
|
||||
public DefaultTypeMapper(TypeAliasAccessor<S> accessor) {
|
||||
this(accessor, Arrays.asList(SimpleTypeInformationMapper.INSTANCE));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link DefaultTypeMapper} using the given {@link TypeAliasAccessor} and {@link TypeInformationMapper}
|
||||
* s.
|
||||
*
|
||||
* @param accessor must not be {@literal null}.
|
||||
* @param mappers must not be {@literal null}.
|
||||
*/
|
||||
public DefaultTypeMapper(TypeAliasAccessor<S> accessor, List<? extends TypeInformationMapper> mappers) {
|
||||
this(accessor, null, mappers);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link DefaultTypeMapper} using the given {@link TypeAliasAccessor}, {@link MappingContext} and
|
||||
* additional {@link TypeInformationMapper}s. Will register a {@link MappingContextTypeInformationMapper} before the
|
||||
* given additional mappers.
|
||||
*
|
||||
* @param accessor must not be {@literal null}.
|
||||
* @param mappingContext
|
||||
* @param additionalMappers must not be {@literal null}.
|
||||
*/
|
||||
public DefaultTypeMapper(TypeAliasAccessor<S> accessor,
|
||||
MappingContext<? extends PersistentEntity<?, ?>, ?> mappingContext,
|
||||
List<? extends TypeInformationMapper> additionalMappers) {
|
||||
|
||||
Assert.notNull(accessor);
|
||||
Assert.notNull(additionalMappers);
|
||||
|
||||
List<TypeInformationMapper> mappers = new ArrayList<TypeInformationMapper>(additionalMappers.size() + 1);
|
||||
if (mappingContext != null) {
|
||||
mappers.add(new MappingContextTypeInformationMapper(mappingContext));
|
||||
}
|
||||
mappers.addAll(additionalMappers);
|
||||
|
||||
this.mappers = Collections.unmodifiableList(mappers);
|
||||
this.accessor = accessor;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.convert.TypeMapper#readType(java.lang.Object)
|
||||
*/
|
||||
public TypeInformation<?> readType(S source) {
|
||||
|
||||
Assert.notNull(source);
|
||||
Object alias = accessor.readAliasFrom(source);
|
||||
|
||||
if (alias == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
for (TypeInformationMapper mapper : mappers) {
|
||||
TypeInformation<?> type = mapper.resolveTypeFrom(alias);
|
||||
|
||||
if (type != null) {
|
||||
return type;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.convert.TypeMapper#readType(java.lang.Object, org.springframework.data.util.TypeInformation)
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> TypeInformation<? extends T> readType(S source, TypeInformation<T> basicType) {
|
||||
|
||||
Assert.notNull(source);
|
||||
Class<?> documentsTargetType = getDefaultedTypeToBeUsed(source);
|
||||
|
||||
if (documentsTargetType == null) {
|
||||
return basicType;
|
||||
}
|
||||
|
||||
Class<T> rawType = basicType == null ? null : basicType.getType();
|
||||
|
||||
boolean isMoreConcreteCustomType = rawType == null ? true : rawType.isAssignableFrom(documentsTargetType)
|
||||
&& !rawType.equals(documentsTargetType);
|
||||
return isMoreConcreteCustomType ? (TypeInformation<? extends T>) ClassTypeInformation.from(documentsTargetType)
|
||||
: basicType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the type discovered through {@link #readType(Object)} but defaulted to the one returned by
|
||||
* {@link #getFallbackTypeFor(Object)}.
|
||||
*
|
||||
* @param source
|
||||
* @return
|
||||
*/
|
||||
private Class<?> getDefaultedTypeToBeUsed(S source) {
|
||||
|
||||
TypeInformation<?> documentsTargetTypeInformation = readType(source);
|
||||
documentsTargetTypeInformation = documentsTargetTypeInformation == null ? getFallbackTypeFor(source)
|
||||
: documentsTargetTypeInformation;
|
||||
return documentsTargetTypeInformation == null ? null : documentsTargetTypeInformation.getType();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the type fallback {@link TypeInformation} in case none could be extracted from the given source.
|
||||
*
|
||||
* @param source will never be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
protected TypeInformation<?> getFallbackTypeFor(S source) {
|
||||
return null;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.convert.TypeMapper#writeType(java.lang.Class, java.lang.Object)
|
||||
*/
|
||||
public void writeType(Class<?> type, S dbObject) {
|
||||
writeType(ClassTypeInformation.from(type), dbObject);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.convert.TypeMapper#writeType(org.springframework.data.util.TypeInformation, java.lang.Object)
|
||||
*/
|
||||
public void writeType(TypeInformation<?> info, S sink) {
|
||||
|
||||
Assert.notNull(info);
|
||||
|
||||
for (TypeInformationMapper mapper : mappers) {
|
||||
Object alias = mapper.createAliasFor(info);
|
||||
if (alias != null) {
|
||||
accessor.writeTypeTo(sink, alias);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright 2011-2012 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.convert;
|
||||
|
||||
import org.springframework.core.convert.ConversionService;
|
||||
import org.springframework.data.mapping.PersistentEntity;
|
||||
import org.springframework.data.mapping.PersistentProperty;
|
||||
import org.springframework.data.mapping.context.MappingContext;
|
||||
|
||||
/**
|
||||
* Combined {@link EntityReader} and {@link EntityWriter} and add the ability to access a {@link MappingContext} and
|
||||
* {@link ConversionService}.
|
||||
*
|
||||
* @param <E> the concrete {@link PersistentEntity} implementation the converter is based on.
|
||||
* @param <P> the concrete {@link PersistentProperty} implementation the converter is based on.
|
||||
* @param <T> the most common type the {@link EntityConverter} can actually convert.
|
||||
* @param <S> the store specific source and sink an {@link EntityConverter} can deal with.
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public interface EntityConverter<E extends PersistentEntity<?, P>, P extends PersistentProperty<P>, T, S> extends
|
||||
EntityReader<T, S>, EntityWriter<T, S> {
|
||||
|
||||
/**
|
||||
* Returns the underlying {@link MappingContext} used by the converter.
|
||||
*
|
||||
* @return never {@literal null}
|
||||
*/
|
||||
MappingContext<? extends E, P> getMappingContext();
|
||||
|
||||
/**
|
||||
* Returns the underlying {@link ConversionService} used by the converter.
|
||||
*
|
||||
* @return never {@literal null}.
|
||||
*/
|
||||
ConversionService getConversionService();
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright 2012-2013 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.convert;
|
||||
|
||||
import org.springframework.data.mapping.PersistentEntity;
|
||||
import org.springframework.data.mapping.PersistentProperty;
|
||||
import org.springframework.data.mapping.model.ParameterValueProvider;
|
||||
|
||||
/**
|
||||
* SPI to abstract strategies to create instances for {@link PersistentEntity}s.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public interface EntityInstantiator {
|
||||
|
||||
/**
|
||||
* Creates a new instance of the given entity using the given source to pull data from.
|
||||
*
|
||||
* @param entity will not be {@literal null}.
|
||||
* @param provider will not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
<T, E extends PersistentEntity<? extends T, P>, P extends PersistentProperty<P>> T createInstance(E entity,
|
||||
ParameterValueProvider<P> provider);
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
/*
|
||||
* Copyright 2012 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.convert;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.data.mapping.PersistentEntity;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Simple value object allowing access to {@link EntityInstantiator} instances for a given type falling back to a
|
||||
* default one.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public class EntityInstantiators {
|
||||
|
||||
private final EntityInstantiator fallback;
|
||||
private final Map<Class<?>, EntityInstantiator> customInstantiators;
|
||||
|
||||
/**
|
||||
* Creates a new {@link EntityInstantiators} using the default fallback instantiator and no custom ones.
|
||||
*/
|
||||
public EntityInstantiators() {
|
||||
this(Collections.<Class<?>, EntityInstantiator> emptyMap());
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link EntityInstantiators} using the given {@link EntityInstantiator} as fallback.
|
||||
*
|
||||
* @param fallback must not be {@literal null}.
|
||||
*/
|
||||
public EntityInstantiators(EntityInstantiator fallback) {
|
||||
this(fallback, Collections.<Class<?>, EntityInstantiator> emptyMap());
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link EntityInstantiators} using the default fallback instantiator and the given custom ones.
|
||||
*
|
||||
* @param customInstantiators must not be {@literal null}.
|
||||
*/
|
||||
public EntityInstantiators(Map<Class<?>, EntityInstantiator> customInstantiators) {
|
||||
this(ReflectionEntityInstantiator.INSTANCE, customInstantiators);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link EntityInstantiator} using the given fallback {@link EntityInstantiator} and the given custom
|
||||
* ones.
|
||||
*
|
||||
* @param fallback must not be {@literal null}.
|
||||
* @param customInstantiators must not be {@literal null}.
|
||||
*/
|
||||
public EntityInstantiators(EntityInstantiator defaultInstantiator,
|
||||
Map<Class<?>, EntityInstantiator> customInstantiators) {
|
||||
|
||||
Assert.notNull(defaultInstantiator);
|
||||
Assert.notNull(customInstantiators);
|
||||
|
||||
this.fallback = defaultInstantiator;
|
||||
this.customInstantiators = customInstantiators;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link EntityInstantiator} to be used to create the given {@link PersistentEntity}.
|
||||
*
|
||||
* @param entity must not be {@literal null}.
|
||||
* @return will never be {@literal null}.
|
||||
*/
|
||||
public EntityInstantiator getInstantiatorFor(PersistentEntity<?, ?> entity) {
|
||||
|
||||
Assert.notNull(entity);
|
||||
Class<?> type = entity.getType();
|
||||
|
||||
if (!customInstantiators.containsKey(type)) {
|
||||
return fallback;
|
||||
}
|
||||
|
||||
EntityInstantiator instantiator = customInstantiators.get(entity.getType());
|
||||
return instantiator == null ? fallback : instantiator;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Copyright (c) 2011 by the original author(s).
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.convert;
|
||||
|
||||
/**
|
||||
* Interface to read object from store specific sources.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public interface EntityReader<T, S> {
|
||||
|
||||
/**
|
||||
* Reads the given source into the given type.
|
||||
*
|
||||
* @param type they type to convert the given source to.
|
||||
* @param source the source to create an object of the given type from.
|
||||
* @return
|
||||
*/
|
||||
<R extends T> R read(Class<R> type, S source);
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Copyright (c) 2011 by the original author(s).
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.convert;
|
||||
|
||||
/**
|
||||
* Interface to write objects into store specific sinks.
|
||||
*
|
||||
* @param <T> the entity type the converter can handle
|
||||
* @param <S> the store specific sink the converter is able to write to
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public interface EntityWriter<T, S> {
|
||||
|
||||
void write(T source, S sink);
|
||||
}
|
||||
@@ -0,0 +1,125 @@
|
||||
/*
|
||||
* Copyright 2011-2012 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.convert;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import org.springframework.data.mapping.PersistentEntity;
|
||||
import org.springframework.data.mapping.context.MappingContext;
|
||||
import org.springframework.data.util.TypeInformation;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* {@link TypeInformationMapper} implementation that can be either set up using a {@link MappingContext} or manually set
|
||||
* up {@link Map} of {@link String} aliases to types. If a {@link MappingContext} is used the {@link Map} will be build
|
||||
* inspecting the {@link PersistentEntity} instances for type alias information.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public class MappingContextTypeInformationMapper implements TypeInformationMapper {
|
||||
|
||||
private final Map<TypeInformation<?>, Object> typeMap;
|
||||
private final MappingContext<? extends PersistentEntity<?, ?>, ?> mappingContext;
|
||||
|
||||
/**
|
||||
* Creates a {@link MappingContextTypeInformationMapper} from the given {@link MappingContext}. Inspects all
|
||||
* {@link PersistentEntity} instances for alias information and builds a {@link Map} of aliases to types from it.
|
||||
*
|
||||
* @param mappingContext must not be {@literal null}.
|
||||
*/
|
||||
public MappingContextTypeInformationMapper(MappingContext<? extends PersistentEntity<?, ?>, ?> mappingContext) {
|
||||
|
||||
Assert.notNull(mappingContext);
|
||||
|
||||
this.typeMap = new HashMap<TypeInformation<?>, Object>();
|
||||
this.mappingContext = mappingContext;
|
||||
|
||||
for (PersistentEntity<?, ?> entity : mappingContext.getPersistentEntities()) {
|
||||
safelyAddToCache(entity.getTypeInformation(), entity.getTypeAlias());
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.convert.TypeInformationMapper#createAliasFor(org.springframework.data.util.TypeInformation)
|
||||
*/
|
||||
public Object createAliasFor(TypeInformation<?> type) {
|
||||
|
||||
Object key = typeMap.get(type);
|
||||
|
||||
if (key != null) {
|
||||
return key;
|
||||
}
|
||||
|
||||
PersistentEntity<?, ?> entity = mappingContext.getPersistentEntity(type);
|
||||
|
||||
if (entity == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
Object alias = entity.getTypeAlias();
|
||||
safelyAddToCache(type, alias);
|
||||
|
||||
return alias;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the given alias to the cache in a {@literal null}-safe manner.
|
||||
*
|
||||
* @param key must not be {@literal null}.
|
||||
* @param alias can be {@literal null}.
|
||||
*/
|
||||
private void safelyAddToCache(TypeInformation<?> key, Object alias) {
|
||||
|
||||
if (alias == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (typeMap.containsValue(alias)) {
|
||||
throw new IllegalArgumentException(String.format(
|
||||
"Detected mapping ambiguity! String %s cannot be mapped to more than one type!", alias));
|
||||
}
|
||||
|
||||
typeMap.put(key, alias);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.convert.TypeInformationMapper#resolveTypeFrom(java.lang.Object)
|
||||
*/
|
||||
public TypeInformation<?> resolveTypeFrom(Object alias) {
|
||||
|
||||
if (alias == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
for (Entry<TypeInformation<?>, Object> entry : typeMap.entrySet()) {
|
||||
if (entry.getValue().equals(alias)) {
|
||||
return entry.getKey();
|
||||
}
|
||||
}
|
||||
|
||||
for (PersistentEntity<?, ?> entity : mappingContext.getPersistentEntities()) {
|
||||
if (alias.equals(entity.getTypeAlias())) {
|
||||
return entity.getTypeInformation();
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright 2011 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.convert;
|
||||
|
||||
import static java.lang.annotation.ElementType.*;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import org.springframework.core.convert.converter.Converter;
|
||||
|
||||
/**
|
||||
* Annotation to clarify intended usage of a {@link Converter} as reading converter in case the conversion types leave
|
||||
* room for disambiguation.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
@Target(TYPE)
|
||||
@Documented
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface ReadingConverter {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
* Copyright 2012-2013 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.convert;
|
||||
|
||||
import java.lang.reflect.Array;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.beans.BeanInstantiationException;
|
||||
import org.springframework.beans.BeanUtils;
|
||||
import org.springframework.data.mapping.PersistentEntity;
|
||||
import org.springframework.data.mapping.PersistentProperty;
|
||||
import org.springframework.data.mapping.PreferredConstructor;
|
||||
import org.springframework.data.mapping.PreferredConstructor.Parameter;
|
||||
import org.springframework.data.mapping.model.MappingInstantiationException;
|
||||
import org.springframework.data.mapping.model.ParameterValueProvider;
|
||||
|
||||
/**
|
||||
* {@link EntityInstantiator} that uses the {@link PersistentEntity}'s {@link PreferredConstructor} to instantiate an
|
||||
* instance of the entity via reflection.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public enum ReflectionEntityInstantiator implements EntityInstantiator {
|
||||
|
||||
INSTANCE;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T, E extends PersistentEntity<? extends T, P>, P extends PersistentProperty<P>> T createInstance(E entity,
|
||||
ParameterValueProvider<P> provider) {
|
||||
|
||||
PreferredConstructor<? extends T, P> constructor = entity.getPersistenceConstructor();
|
||||
|
||||
if (constructor == null) {
|
||||
|
||||
try {
|
||||
Class<?> clazz = entity.getType();
|
||||
if (clazz.isArray()) {
|
||||
Class<?> ctype = clazz;
|
||||
int dims = 0;
|
||||
while (ctype.isArray()) {
|
||||
ctype = ctype.getComponentType();
|
||||
dims++;
|
||||
}
|
||||
return (T) Array.newInstance(clazz, dims);
|
||||
} else {
|
||||
return BeanUtils.instantiateClass(entity.getType());
|
||||
}
|
||||
} catch (BeanInstantiationException e) {
|
||||
throw new MappingInstantiationException(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
List<Object> params = new ArrayList<Object>();
|
||||
if (null != provider && constructor.hasParameters()) {
|
||||
for (Parameter<?, P> parameter : constructor.getParameters()) {
|
||||
params.add(provider.getParameterValue(parameter));
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
return BeanUtils.instantiateClass(constructor.getConstructor(), params.toArray());
|
||||
} catch (BeanInstantiationException e) {
|
||||
throw new MappingInstantiationException(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
* Copyright 2011 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.convert;
|
||||
|
||||
import org.springframework.data.util.ClassTypeInformation;
|
||||
import org.springframework.data.util.TypeInformation;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Basic {@link TypeInformationMapper} implementation that interprets the alias handles as fully qualified class name
|
||||
* and tries to load a class with the given name to build {@link TypeInformation}. Returns the fully qualified class
|
||||
* name for alias creation.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public class SimpleTypeInformationMapper implements TypeInformationMapper {
|
||||
|
||||
public static final SimpleTypeInformationMapper INSTANCE = new SimpleTypeInformationMapper();
|
||||
|
||||
/**
|
||||
* Returns the {@link TypeInformation} that shall be used when the given {@link String} value is found as type hint.
|
||||
* The implementation will simply interpret the given value as fully-qualified class name and try to load the class.
|
||||
* Will return {@literal null} in case the given {@link String} is empty.
|
||||
*
|
||||
* @param value the type to load, must not be {@literal null}.
|
||||
* @return the type to be used for the given {@link String} representation or {@literal null} if nothing found or the
|
||||
* class cannot be loaded.
|
||||
*/
|
||||
public TypeInformation<?> resolveTypeFrom(Object alias) {
|
||||
|
||||
if (!(alias instanceof String)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
String value = (String) alias;
|
||||
|
||||
if (!StringUtils.hasText(value)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
return ClassTypeInformation.from(ClassUtils.forName(value, null));
|
||||
} catch (ClassNotFoundException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Turn the given type information into the String representation that shall be stored. Default implementation simply
|
||||
* returns the fully-qualified class name.
|
||||
*
|
||||
* @param typeInformation must not be {@literal null}.
|
||||
* @return the String representation to be stored or {@literal null} if no type information shall be stored.
|
||||
*/
|
||||
public String createAliasFor(TypeInformation<?> type) {
|
||||
|
||||
return type.getType().getName();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright 2011 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.convert;
|
||||
|
||||
/**
|
||||
* Interface to abstract implementations of how to access a type alias from a given source or sink.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public interface TypeAliasAccessor<S> {
|
||||
|
||||
/**
|
||||
* Reads the type alias to be used from the given source.
|
||||
*
|
||||
* @param source
|
||||
* @return can be {@literal null} in case no alias was found.
|
||||
*/
|
||||
Object readAliasFrom(S source);
|
||||
|
||||
/**
|
||||
* Writes the given type alias to the given sink.
|
||||
*
|
||||
* @param sink
|
||||
* @param alias
|
||||
*/
|
||||
void writeTypeTo(S sink, Object alias);
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright 2011 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.convert;
|
||||
|
||||
import org.springframework.data.util.TypeInformation;
|
||||
|
||||
/**
|
||||
* Interface to abstract the mapping from a type alias to the actual type.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public interface TypeInformationMapper {
|
||||
|
||||
/**
|
||||
* Returns the actual {@link TypeInformation} to be used for the given alias.
|
||||
*
|
||||
* @param alias can be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
TypeInformation<?> resolveTypeFrom(Object alias);
|
||||
|
||||
/**
|
||||
* Returns the alias to be used for the given {@link TypeInformation}.
|
||||
*
|
||||
* @param type
|
||||
* @return
|
||||
*/
|
||||
Object createAliasFor(TypeInformation<?> type);
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright 2011 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.convert;
|
||||
|
||||
import org.springframework.data.util.TypeInformation;
|
||||
|
||||
/**
|
||||
* Interface to define strategies how to store type information in a store specific sink or source.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public interface TypeMapper<S> {
|
||||
|
||||
/**
|
||||
* Reads the {@link TypeInformation} from the given source.
|
||||
*
|
||||
* @param source must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
TypeInformation<?> readType(S source);
|
||||
|
||||
/**
|
||||
* Returns the {@link TypeInformation} from the given source if it is a more concrete type than the given default one.
|
||||
*
|
||||
* @param source must not be {@literal null}.
|
||||
* @param defaultType
|
||||
* @return
|
||||
*/
|
||||
<T> TypeInformation<? extends T> readType(S source, TypeInformation<T> defaultType);
|
||||
|
||||
/**
|
||||
* Writes type information for the given type into the given sink.
|
||||
*
|
||||
* @param type must not be {@literal null}.
|
||||
* @param dbObject must not be {@literal null}.
|
||||
*/
|
||||
void writeType(Class<?> type, S dbObject);
|
||||
|
||||
/**
|
||||
* Writes type information for the given {@link TypeInformation} into the given sink.
|
||||
*
|
||||
* @param type must not be {@literal null}.
|
||||
* @param dbObject must not be {@literal null}.
|
||||
*/
|
||||
void writeType(TypeInformation<?> type, S dbObject);
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright 2011 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.convert;
|
||||
|
||||
import static java.lang.annotation.ElementType.*;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import org.springframework.core.convert.converter.Converter;
|
||||
|
||||
/**
|
||||
* Annotation to clarify intended usage of a {@link Converter} as writing converter in case the conversion types leave
|
||||
* room for disambiguation.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
@Target(TYPE)
|
||||
@Documented
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface WritingConverter {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
/**
|
||||
* General purpose conversion framework to read objects from a data store abstraction and write it back.
|
||||
*
|
||||
* @see org.springframework.data.convert.EntityConverter
|
||||
*/
|
||||
package org.springframework.data.convert;
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright 2011 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.crossstore;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.core.convert.ConversionService;
|
||||
|
||||
/**
|
||||
* Interface representing the set of changes in an entity.
|
||||
*
|
||||
* @author Rod Johnson
|
||||
* @author Thomas Risberg
|
||||
*/
|
||||
public interface ChangeSet {
|
||||
|
||||
<T> T get(String key, Class<T> requiredClass, ConversionService cs);
|
||||
|
||||
void set(String key, Object o);
|
||||
|
||||
Map<String, Object> getValues();
|
||||
|
||||
Object removeProperty(String k);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Copyright 2011 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.crossstore;
|
||||
|
||||
/**
|
||||
* Interface introduced to objects exposing ChangeSet information
|
||||
*
|
||||
* @author Rod Johnson
|
||||
* @author Thomas Risberg
|
||||
*/
|
||||
public interface ChangeSetBacked {
|
||||
|
||||
ChangeSet getChangeSet();
|
||||
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
* Copyright 2011 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.crossstore;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.transaction.support.TransactionSynchronization;
|
||||
|
||||
public class ChangeSetBackedTransactionSynchronization implements TransactionSynchronization {
|
||||
|
||||
protected final Logger log = LoggerFactory.getLogger(getClass());
|
||||
|
||||
private final ChangeSetPersister<Object> changeSetPersister;
|
||||
private final ChangeSetBacked entity;
|
||||
private int changeSetTxStatus = -1;
|
||||
|
||||
public ChangeSetBackedTransactionSynchronization(ChangeSetPersister<Object> changeSetPersister, ChangeSetBacked entity) {
|
||||
this.changeSetPersister = changeSetPersister;
|
||||
this.entity = entity;
|
||||
}
|
||||
|
||||
public void afterCommit() {
|
||||
log.debug("After Commit called for " + entity);
|
||||
changeSetPersister.persistState(entity, entity.getChangeSet());
|
||||
changeSetTxStatus = 0;
|
||||
}
|
||||
|
||||
public void afterCompletion(int status) {
|
||||
log.debug("After Completion called with status = " + status);
|
||||
if (changeSetTxStatus == 0) {
|
||||
if (status == STATUS_COMMITTED) {
|
||||
// this is good
|
||||
log.debug("ChangedSetBackedTransactionSynchronization completed successfully for " + this.entity);
|
||||
} else {
|
||||
// this could be bad - TODO: compensate
|
||||
log.error("ChangedSetBackedTransactionSynchronization failed for " + this.entity);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void beforeCommit(boolean readOnly) {
|
||||
}
|
||||
|
||||
public void beforeCompletion() {
|
||||
}
|
||||
|
||||
public void flush() {
|
||||
}
|
||||
|
||||
public void resume() {
|
||||
throw new IllegalStateException(
|
||||
"ChangedSetBackedTransactionSynchronization does not support transaction suspension currently.");
|
||||
}
|
||||
|
||||
public void suspend() {
|
||||
throw new IllegalStateException(
|
||||
"ChangedSetBackedTransactionSynchronization does not support transaction suspension currently.");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* Copyright 2011 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.crossstore;
|
||||
|
||||
import org.springframework.dao.DataAccessException;
|
||||
|
||||
/**
|
||||
* Interface to be implemented by classes that can synchronize between data stores and ChangeSets.
|
||||
*
|
||||
* @param <K> entity key
|
||||
* @author Rod Johnson
|
||||
*/
|
||||
public interface ChangeSetPersister<K> {
|
||||
|
||||
String ID_KEY = "_id";
|
||||
String CLASS_KEY = "_class";
|
||||
|
||||
/**
|
||||
* TODO how to tell when not found? throw exception?
|
||||
*/
|
||||
void getPersistentState(Class<? extends ChangeSetBacked> entityClass, K key, ChangeSet changeSet)
|
||||
throws DataAccessException, NotFoundException;
|
||||
|
||||
/**
|
||||
* Return id
|
||||
*
|
||||
* @param entity
|
||||
* @param cs
|
||||
* @return
|
||||
* @throws DataAccessException
|
||||
*/
|
||||
K getPersistentId(ChangeSetBacked entity, ChangeSet cs) throws DataAccessException;
|
||||
|
||||
/**
|
||||
* Return key
|
||||
*
|
||||
* @param entity
|
||||
* @param cs Key may be null if not persistent
|
||||
* @return
|
||||
* @throws DataAccessException
|
||||
*/
|
||||
K persistState(ChangeSetBacked entity, ChangeSet cs) throws DataAccessException;
|
||||
|
||||
/**
|
||||
* Exception thrown in alternate control flow if getPersistentState finds no entity data.
|
||||
*/
|
||||
class NotFoundException extends Exception {
|
||||
|
||||
private static final long serialVersionUID = -8604207973816331140L;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* Copyright 2011 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.crossstore;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.core.convert.ConversionService;
|
||||
|
||||
/**
|
||||
* Simple ChangeSet implementation backed by a HashMap.
|
||||
*
|
||||
* @author Thomas Risberg
|
||||
* @author Rod Johnson
|
||||
*/
|
||||
public class HashMapChangeSet implements ChangeSet {
|
||||
|
||||
private final Map<String, Object> values;
|
||||
|
||||
public HashMapChangeSet(Map<String, Object> values) {
|
||||
this.values = values;
|
||||
}
|
||||
|
||||
public HashMapChangeSet() {
|
||||
this(new HashMap<String, Object>());
|
||||
}
|
||||
|
||||
public void set(String key, Object o) {
|
||||
values.put(key, o);
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return "HashMapChangeSet: values=[" + values + "]";
|
||||
}
|
||||
|
||||
public Map<String, Object> getValues() {
|
||||
return Collections.unmodifiableMap(values);
|
||||
}
|
||||
|
||||
public Object removeProperty(String k) {
|
||||
return this.values.remove(k);
|
||||
}
|
||||
|
||||
public <T> T get(String key, Class<T> requiredClass, ConversionService conversionService) {
|
||||
return conversionService.convert(values.get(key), requiredClass);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
/**
|
||||
* Support for cross-store persistence.
|
||||
*/
|
||||
package org.springframework.data.crossstore;
|
||||
87
src/main/java/org/springframework/data/domain/Auditable.java
Normal file
87
src/main/java/org/springframework/data/domain/Auditable.java
Normal file
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
* Copyright 2008-2010 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.domain;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import org.joda.time.DateTime;
|
||||
|
||||
/**
|
||||
* Interface for auditable entities. Allows storing and retrieving creation and modification information. The changing
|
||||
* instance (typically some user) is to be defined by a generics definition.
|
||||
*
|
||||
* @param <U> the auditing type. Typically some kind of user.
|
||||
* @param <ID> the type of the audited type's identifier
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public interface Auditable<U, ID extends Serializable> extends Persistable<ID> {
|
||||
|
||||
/**
|
||||
* Returns the user who created this entity.
|
||||
*
|
||||
* @return the createdBy
|
||||
*/
|
||||
U getCreatedBy();
|
||||
|
||||
/**
|
||||
* Sets the user who created this entity.
|
||||
*
|
||||
* @param createdBy the creating entity to set
|
||||
*/
|
||||
void setCreatedBy(final U createdBy);
|
||||
|
||||
/**
|
||||
* Returns the creation date of the entity.
|
||||
*
|
||||
* @return the createdDate
|
||||
*/
|
||||
DateTime getCreatedDate();
|
||||
|
||||
/**
|
||||
* Sets the creation date of the entity.
|
||||
*
|
||||
* @param creationDate the creation date to set
|
||||
*/
|
||||
void setCreatedDate(final DateTime creationDate);
|
||||
|
||||
/**
|
||||
* Returns the user who modified the entity lastly.
|
||||
*
|
||||
* @return the lastModifiedBy
|
||||
*/
|
||||
U getLastModifiedBy();
|
||||
|
||||
/**
|
||||
* Sets the user who modified the entity lastly.
|
||||
*
|
||||
* @param lastModifiedBy the last modifying entity to set
|
||||
*/
|
||||
void setLastModifiedBy(final U lastModifiedBy);
|
||||
|
||||
/**
|
||||
* Returns the date of the last modification.
|
||||
*
|
||||
* @return the lastModifiedDate
|
||||
*/
|
||||
DateTime getLastModifiedDate();
|
||||
|
||||
/**
|
||||
* Sets the date of the last modification.
|
||||
*
|
||||
* @param lastModifiedDate the date of the last modification to set
|
||||
*/
|
||||
void setLastModifiedDate(final DateTime lastModifiedDate);
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright 2008-2010 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.domain;
|
||||
|
||||
/**
|
||||
* Interface for components that are aware of the application's current auditor. This will be some kind of user mostly.
|
||||
*
|
||||
* @param <T> the type of the auditing instance
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public interface AuditorAware<T> {
|
||||
|
||||
/**
|
||||
* Returns the current auditor of the application.
|
||||
*
|
||||
* @return the current auditor
|
||||
*/
|
||||
T getCurrentAuditor();
|
||||
}
|
||||
120
src/main/java/org/springframework/data/domain/Page.java
Normal file
120
src/main/java/org/springframework/data/domain/Page.java
Normal file
@@ -0,0 +1,120 @@
|
||||
/*
|
||||
* Copyright 2008-2010 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.domain;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* A page is a sublist of a list of objects. It allows gain information about the position of it in the containing
|
||||
* entire list.
|
||||
*
|
||||
* @param <T>
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public interface Page<T> extends Iterable<T> {
|
||||
|
||||
/**
|
||||
* Returns the number of the current page. Is always positive and less that {@code Page#getTotalPages()}.
|
||||
*
|
||||
* @return the number of the current page
|
||||
*/
|
||||
int getNumber();
|
||||
|
||||
/**
|
||||
* Returns the size of the page.
|
||||
*
|
||||
* @return the size of the page
|
||||
*/
|
||||
int getSize();
|
||||
|
||||
/**
|
||||
* Returns the number of total pages.
|
||||
*
|
||||
* @return the number of toral pages
|
||||
*/
|
||||
int getTotalPages();
|
||||
|
||||
/**
|
||||
* Returns the number of elements currently on this page.
|
||||
*
|
||||
* @return the number of elements currently on this page
|
||||
*/
|
||||
int getNumberOfElements();
|
||||
|
||||
/**
|
||||
* Returns the total amount of elements.
|
||||
*
|
||||
* @return the total amount of elements
|
||||
*/
|
||||
long getTotalElements();
|
||||
|
||||
/**
|
||||
* Returns if there is a previous page.
|
||||
*
|
||||
* @return if there is a previous page
|
||||
*/
|
||||
boolean hasPreviousPage();
|
||||
|
||||
/**
|
||||
* Returns whether the current page is the first one.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
boolean isFirstPage();
|
||||
|
||||
/**
|
||||
* Returns if there is a next page.
|
||||
*
|
||||
* @return if there is a next page
|
||||
*/
|
||||
boolean hasNextPage();
|
||||
|
||||
/**
|
||||
* Returns whether the current page is the last one.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
boolean isLastPage();
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see java.lang.Iterable#iterator()
|
||||
*/
|
||||
Iterator<T> iterator();
|
||||
|
||||
/**
|
||||
* Returns the page content as {@link List}.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
List<T> getContent();
|
||||
|
||||
/**
|
||||
* Returns whether the {@link Page} has content at all.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
boolean hasContent();
|
||||
|
||||
/**
|
||||
* Returns the sorting parameters for the page.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
Sort getSort();
|
||||
}
|
||||
255
src/main/java/org/springframework/data/domain/PageImpl.java
Normal file
255
src/main/java/org/springframework/data/domain/PageImpl.java
Normal file
@@ -0,0 +1,255 @@
|
||||
/*
|
||||
* Copyright 2008-2010 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.domain;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Basic {@code Page} implementation.
|
||||
*
|
||||
* @param <T> the type of which the page consists.
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public class PageImpl<T> implements Page<T>, Serializable {
|
||||
|
||||
private static final long serialVersionUID = 867755909294344406L;
|
||||
|
||||
private final List<T> content = new ArrayList<T>();
|
||||
private final Pageable pageable;
|
||||
private final long total;
|
||||
|
||||
/**
|
||||
* Constructor of {@code PageImpl}.
|
||||
*
|
||||
* @param content the content of this page
|
||||
* @param pageable the paging information
|
||||
* @param total the total amount of items available
|
||||
*/
|
||||
public PageImpl(List<T> content, Pageable pageable, long total) {
|
||||
|
||||
if (null == content) {
|
||||
throw new IllegalArgumentException("Content must not be null!");
|
||||
}
|
||||
|
||||
this.content.addAll(content);
|
||||
this.total = total;
|
||||
this.pageable = pageable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link PageImpl} with the given content. This will result in the created {@link Page} being identical
|
||||
* to the entire {@link List}.
|
||||
*
|
||||
* @param content
|
||||
*/
|
||||
public PageImpl(List<T> content) {
|
||||
|
||||
this(content, null, (null == content) ? 0 : content.size());
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see org.springframework.data.domain.Page#getNumber()
|
||||
*/
|
||||
public int getNumber() {
|
||||
|
||||
return pageable == null ? 0 : pageable.getPageNumber();
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see org.springframework.data.domain.Page#getSize()
|
||||
*/
|
||||
public int getSize() {
|
||||
|
||||
return pageable == null ? 0 : pageable.getPageSize();
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see org.springframework.data.domain.Page#getTotalPages()
|
||||
*/
|
||||
public int getTotalPages() {
|
||||
|
||||
return getSize() == 0 ? 0 : (int) Math.ceil((double) total / (double) getSize());
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see org.springframework.data.domain.Page#getNumberOfElements()
|
||||
*/
|
||||
public int getNumberOfElements() {
|
||||
|
||||
return content.size();
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see org.springframework.data.domain.Page#getTotalElements()
|
||||
*/
|
||||
public long getTotalElements() {
|
||||
|
||||
return total;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see org.springframework.data.domain.Page#hasPreviousPage()
|
||||
*/
|
||||
public boolean hasPreviousPage() {
|
||||
|
||||
return getNumber() > 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see org.springframework.data.domain.Page#isFirstPage()
|
||||
*/
|
||||
public boolean isFirstPage() {
|
||||
|
||||
return !hasPreviousPage();
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see org.springframework.data.domain.Page#hasNextPage()
|
||||
*/
|
||||
public boolean hasNextPage() {
|
||||
|
||||
return ((getNumber() + 1) * getSize()) < total;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see org.springframework.data.domain.Page#isLastPage()
|
||||
*/
|
||||
public boolean isLastPage() {
|
||||
|
||||
return !hasNextPage();
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see org.springframework.data.domain.Page#iterator()
|
||||
*/
|
||||
public Iterator<T> iterator() {
|
||||
|
||||
return content.iterator();
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see org.springframework.data.domain.Page#asList()
|
||||
*/
|
||||
public List<T> getContent() {
|
||||
|
||||
return Collections.unmodifiableList(content);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see org.springframework.data.domain.Page#hasContent()
|
||||
*/
|
||||
public boolean hasContent() {
|
||||
|
||||
return !content.isEmpty();
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see org.springframework.data.domain.Page#getSort()
|
||||
*/
|
||||
public Sort getSort() {
|
||||
|
||||
return pageable == null ? null : pageable.getSort();
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see java.lang.Object#toString()
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
|
||||
String contentType = "UNKNOWN";
|
||||
|
||||
if (content.size() > 0) {
|
||||
contentType = content.get(0).getClass().getName();
|
||||
}
|
||||
|
||||
return String.format("Page %s of %d containing %s instances", getNumber(), getTotalPages(), contentType);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see java.lang.Object#equals(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!(obj instanceof PageImpl<?>)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
PageImpl<?> that = (PageImpl<?>) obj;
|
||||
|
||||
boolean totalEqual = this.total == that.total;
|
||||
boolean contentEqual = this.content.equals(that.content);
|
||||
boolean pageableEqual = this.pageable == null ? that.pageable == null : this.pageable.equals(that.pageable);
|
||||
|
||||
return totalEqual && contentEqual && pageableEqual;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see java.lang.Object#hashCode()
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
|
||||
int result = 17;
|
||||
|
||||
result = 31 * result + (int) (total ^ total >>> 32);
|
||||
result = 31 * result + (pageable == null ? 0 : pageable.hashCode());
|
||||
result = 31 * result + content.hashCode();
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
164
src/main/java/org/springframework/data/domain/PageRequest.java
Normal file
164
src/main/java/org/springframework/data/domain/PageRequest.java
Normal file
@@ -0,0 +1,164 @@
|
||||
/*
|
||||
* Copyright 2008-2012 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.domain;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import org.springframework.data.domain.Sort.Direction;
|
||||
|
||||
/**
|
||||
* Basic Java Bean implementation of {@code Pageable}.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public class PageRequest implements Pageable, Serializable {
|
||||
|
||||
private static final long serialVersionUID = 8280485938848398236L;
|
||||
|
||||
private final int page;
|
||||
private final int size;
|
||||
private final Sort sort;
|
||||
|
||||
/**
|
||||
* Creates a new {@link PageRequest}. Pages are zero indexed, thus providing 0 for {@code page} will return the first
|
||||
* page.
|
||||
*
|
||||
* @param size
|
||||
* @param page
|
||||
*/
|
||||
public PageRequest(int page, int size) {
|
||||
|
||||
this(page, size, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link PageRequest} with sort parameters applied.
|
||||
*
|
||||
* @param page
|
||||
* @param size
|
||||
* @param direction
|
||||
* @param properties
|
||||
*/
|
||||
public PageRequest(int page, int size, Direction direction, String... properties) {
|
||||
|
||||
this(page, size, new Sort(direction, properties));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link PageRequest} with sort parameters applied.
|
||||
*
|
||||
* @param page
|
||||
* @param size
|
||||
* @param sort
|
||||
*/
|
||||
public PageRequest(int page, int size, Sort sort) {
|
||||
|
||||
if (0 > page) {
|
||||
throw new IllegalArgumentException("Page index must not be less than zero!");
|
||||
}
|
||||
|
||||
if (0 >= size) {
|
||||
throw new IllegalArgumentException("Page size must not be less than or equal to zero!");
|
||||
}
|
||||
|
||||
this.page = page;
|
||||
this.size = size;
|
||||
this.sort = sort;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see org.springframework.data.domain.Pageable#getPageSize()
|
||||
*/
|
||||
public int getPageSize() {
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see org.springframework.data.domain.Pageable#getPageNumber()
|
||||
*/
|
||||
public int getPageNumber() {
|
||||
|
||||
return page;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see org.springframework.data.domain.Pageable#getFirstItem()
|
||||
*/
|
||||
public int getOffset() {
|
||||
|
||||
return page * size;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see org.springframework.data.domain.Pageable#getSort()
|
||||
*/
|
||||
public Sort getSort() {
|
||||
|
||||
return sort;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see java.lang.Object#equals(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(final Object obj) {
|
||||
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!(obj instanceof PageRequest)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
PageRequest that = (PageRequest) obj;
|
||||
|
||||
boolean pageEqual = this.page == that.page;
|
||||
boolean sizeEqual = this.size == that.size;
|
||||
|
||||
boolean sortEqual = this.sort == null ? that.sort == null : this.sort.equals(that.sort);
|
||||
|
||||
return pageEqual && sizeEqual && sortEqual;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see java.lang.Object#hashCode()
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
|
||||
int result = 17;
|
||||
|
||||
result = 31 * result + page;
|
||||
result = 31 * result + size;
|
||||
result = 31 * result + (null == sort ? 0 : sort.hashCode());
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
52
src/main/java/org/springframework/data/domain/Pageable.java
Normal file
52
src/main/java/org/springframework/data/domain/Pageable.java
Normal file
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Copyright 2008-2010 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.domain;
|
||||
|
||||
/**
|
||||
* Abstract interface for pagination information.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public interface Pageable {
|
||||
|
||||
/**
|
||||
* Returns the page to be returned.
|
||||
*
|
||||
* @return the page to be returned.
|
||||
*/
|
||||
int getPageNumber();
|
||||
|
||||
/**
|
||||
* Returns the number of items to be returned.
|
||||
*
|
||||
* @return the number of items of that page
|
||||
*/
|
||||
int getPageSize();
|
||||
|
||||
/**
|
||||
* Returns the offset to be taken according to the underlying page and page size.
|
||||
*
|
||||
* @return the offset to be taken
|
||||
*/
|
||||
int getOffset();
|
||||
|
||||
/**
|
||||
* Returns the sorting parameters.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
Sort getSort();
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright 2008-2011 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.domain;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* Simple interface for entities.
|
||||
*
|
||||
* @param <ID> the type of the identifier
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public interface Persistable<ID extends Serializable> extends Serializable {
|
||||
|
||||
/**
|
||||
* Returns the id of the entity.
|
||||
*
|
||||
* @return the id
|
||||
*/
|
||||
ID getId();
|
||||
|
||||
/**
|
||||
* Returns if the {@code Persistable} is new or was persisted already.
|
||||
*
|
||||
* @return if the object is new
|
||||
*/
|
||||
boolean isNew();
|
||||
}
|
||||
359
src/main/java/org/springframework/data/domain/Sort.java
Normal file
359
src/main/java/org/springframework/data/domain/Sort.java
Normal file
@@ -0,0 +1,359 @@
|
||||
/*
|
||||
* Copyright 2008-2013 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.domain;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Sort option for queries. You have to provide at least a list of properties to sort for that must not include
|
||||
* {@literal null} or empty strings. The direction defaults to {@link Sort#DEFAULT_DIRECTION}.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public class Sort implements Iterable<org.springframework.data.domain.Sort.Order>, Serializable {
|
||||
|
||||
private static final long serialVersionUID = 5737186511678863905L;
|
||||
public static final Direction DEFAULT_DIRECTION = Direction.ASC;
|
||||
|
||||
private final List<Order> orders;
|
||||
|
||||
/**
|
||||
* Creates a new {@link Sort} instance using the given {@link Order}s.
|
||||
*
|
||||
* @param orders must not be {@literal null}.
|
||||
*/
|
||||
public Sort(Order... orders) {
|
||||
this(Arrays.asList(orders));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link Sort} instance.
|
||||
*
|
||||
* @param orders must not be {@literal null} or contain {@literal null}.
|
||||
*/
|
||||
public Sort(List<Order> orders) {
|
||||
|
||||
if (null == orders || orders.isEmpty()) {
|
||||
throw new IllegalArgumentException("You have to provide at least one sort property to sort by!");
|
||||
}
|
||||
|
||||
this.orders = orders;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link Sort} instance. Order defaults to {@value Direction#ASC}.
|
||||
*
|
||||
* @param properties must not be {@literal null} or contain {@literal null} or empty strings
|
||||
*/
|
||||
public Sort(String... properties) {
|
||||
this(DEFAULT_DIRECTION, properties);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link Sort} instance.
|
||||
*
|
||||
* @param direction defaults to {@linke Sort#DEFAULT_DIRECTION} (for {@literal null} cases, too)
|
||||
* @param properties must not be {@literal null} or contain {@literal null} or empty strings
|
||||
*/
|
||||
public Sort(Direction direction, String... properties) {
|
||||
this(direction, properties == null ? new ArrayList<String>() : Arrays.asList(properties));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link Sort} instance.
|
||||
*
|
||||
* @param direction
|
||||
* @param properties
|
||||
*/
|
||||
public Sort(Direction direction, List<String> properties) {
|
||||
|
||||
if (properties == null || properties.isEmpty()) {
|
||||
throw new IllegalArgumentException("You have to provide at least one property to sort by!");
|
||||
}
|
||||
|
||||
this.orders = new ArrayList<Order>(properties.size());
|
||||
|
||||
for (String property : properties) {
|
||||
this.orders.add(new Order(direction, property));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new {@link Sort} consisting of the {@link Order}s of the current {@link Sort} combined with the given
|
||||
* ones.
|
||||
*
|
||||
* @param sort can be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public Sort and(Sort sort) {
|
||||
|
||||
if (sort == null) {
|
||||
return this;
|
||||
}
|
||||
|
||||
ArrayList<Order> these = new ArrayList<Order>(this.orders);
|
||||
|
||||
for (Order order : sort) {
|
||||
these.add(order);
|
||||
}
|
||||
|
||||
return new Sort(these);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the order registered for the given property.
|
||||
*
|
||||
* @param property
|
||||
* @return
|
||||
*/
|
||||
public Order getOrderFor(String property) {
|
||||
|
||||
for (Order order : this) {
|
||||
if (order.getProperty().equals(property)) {
|
||||
return order;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see java.lang.Iterable#iterator()
|
||||
*/
|
||||
public Iterator<Order> iterator() {
|
||||
return this.orders.iterator();
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see java.lang.Object#equals(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!(obj instanceof Sort)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Sort that = (Sort) obj;
|
||||
|
||||
return this.orders.equals(that.orders);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see java.lang.Object#hashCode()
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
|
||||
int result = 17;
|
||||
result = 31 * result + orders.hashCode();
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see java.lang.Object#toString()
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return StringUtils.collectionToCommaDelimitedString(orders);
|
||||
}
|
||||
|
||||
/**
|
||||
* Enumeration for sort directions.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public static enum Direction {
|
||||
|
||||
ASC, DESC;
|
||||
|
||||
/**
|
||||
* Returns the {@link Direction} enum for the given {@link String} value.
|
||||
*
|
||||
* @param value
|
||||
* @return
|
||||
*/
|
||||
public static Direction fromString(String value) {
|
||||
|
||||
try {
|
||||
return Direction.valueOf(value.toUpperCase(Locale.US));
|
||||
} catch (Exception e) {
|
||||
throw new IllegalArgumentException(String.format(
|
||||
"Invalid value '%s' for orders given! Has to be either 'desc' or 'asc' (case insensitive).", value), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* PropertyPath implements the pairing of an {@link Direction} and a property. It is used to provide input for
|
||||
* {@link Sort}
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public static class Order implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1522511010900108987L;
|
||||
|
||||
private final Direction direction;
|
||||
private final String property;
|
||||
|
||||
/**
|
||||
* Creates a new {@link Order} instance. if order is {@literal null} then order defaults to
|
||||
* {@link Sort#DEFAULT_DIRECTION}
|
||||
*
|
||||
* @param direction can be {@literal null}, will default to {@link Sort#DEFAULT_DIRECTION}
|
||||
* @param property must not be {@literal null} or empty.
|
||||
*/
|
||||
public Order(Direction direction, String property) {
|
||||
|
||||
if (!StringUtils.hasText(property)) {
|
||||
throw new IllegalArgumentException("Property must not null or empty!");
|
||||
}
|
||||
|
||||
this.direction = direction == null ? DEFAULT_DIRECTION : direction;
|
||||
this.property = property;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link Order} instance. Takes a single property. Direction defaults to
|
||||
* {@link Sort#DEFAULT_DIRECTION}.
|
||||
*
|
||||
* @param property must not be {@literal null} or empty.
|
||||
*/
|
||||
public Order(String property) {
|
||||
this(DEFAULT_DIRECTION, property);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated use {@link Sort#Sort(Direction, List)} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
public static List<Order> create(Direction direction, Iterable<String> properties) {
|
||||
|
||||
List<Order> orders = new ArrayList<Sort.Order>();
|
||||
for (String property : properties) {
|
||||
orders.add(new Order(direction, property));
|
||||
}
|
||||
return orders;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the order the property shall be sorted for.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public Direction getDirection() {
|
||||
return direction;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the property to order for.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public String getProperty() {
|
||||
return property;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether sorting for this property shall be ascending.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public boolean isAscending() {
|
||||
return this.direction.equals(Direction.ASC);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new {@link Order} with the given {@link Order}.
|
||||
*
|
||||
* @param order
|
||||
* @return
|
||||
*/
|
||||
public Order with(Direction order) {
|
||||
return new Order(order, this.property);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new {@link Sort} instance for the given properties.
|
||||
*
|
||||
* @param properties
|
||||
* @return
|
||||
*/
|
||||
public Sort withProperties(String... properties) {
|
||||
return new Sort(this.direction, properties);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see java.lang.Object#hashCode()
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
|
||||
int result = 17;
|
||||
|
||||
result = 31 * result + direction.hashCode();
|
||||
result = 31 * result + property.hashCode();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see java.lang.Object#equals(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!(obj instanceof Order)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Order that = (Order) obj;
|
||||
|
||||
return this.direction.equals(that.direction) && this.property.equals(that.property);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see java.lang.Object#toString()
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format("%s: %s", property, direction);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* Copyright 2012 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.domain.jaxb;
|
||||
|
||||
import javax.xml.bind.annotation.adapters.XmlAdapter;
|
||||
|
||||
import org.springframework.data.domain.Sort.Order;
|
||||
import org.springframework.data.domain.jaxb.SpringDataJaxb.OrderDto;
|
||||
|
||||
/**
|
||||
* XmlAdapter to convert {@link Order} instances into {@link OrderDto}s and vice versa.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public class OrderAdapter extends XmlAdapter<OrderDto, Order> {
|
||||
|
||||
public static final OrderAdapter INSTANCE = new OrderAdapter();
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see javax.xml.bind.annotation.adapters.XmlAdapter#marshal(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public OrderDto marshal(Order order) throws Exception {
|
||||
|
||||
if (order == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
OrderDto dto = new OrderDto();
|
||||
dto.direction = order.getDirection();
|
||||
dto.property = order.getProperty();
|
||||
return dto;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see javax.xml.bind.annotation.adapters.XmlAdapter#unmarshal(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public Order unmarshal(OrderDto source) throws Exception {
|
||||
return source == null ? null : new Order(source.direction, source.property);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
* Copyright 2012 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.domain.jaxb;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import javax.xml.bind.annotation.adapters.XmlAdapter;
|
||||
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.jaxb.SpringDataJaxb.PageDto;
|
||||
import org.springframework.hateoas.Link;
|
||||
|
||||
/**
|
||||
* {@link XmlAdapter} to convert {@link Page} instances into {@link PageDto} instances and vice versa.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public class PageAdapter extends XmlAdapter<PageDto, Page<Object>> {
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see javax.xml.bind.annotation.adapters.XmlAdapter#marshal(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public PageDto marshal(Page<Object> source) throws Exception {
|
||||
|
||||
if (source == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
PageDto dto = new PageDto();
|
||||
dto.content = source.getContent();
|
||||
dto.add(getLinks(source));
|
||||
|
||||
return dto;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see javax.xml.bind.annotation.adapters.XmlAdapter#unmarshal(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public Page<Object> unmarshal(PageDto v) throws Exception {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return additional links that shall be added to the {@link PageDto}.
|
||||
*
|
||||
* @param source the source {@link Page}.
|
||||
* @return
|
||||
*/
|
||||
protected List<Link> getLinks(Page<?> source) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
* Copyright 2012 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.domain.jaxb;
|
||||
|
||||
import java.util.Collections;
|
||||
|
||||
import javax.xml.bind.annotation.adapters.XmlAdapter;
|
||||
|
||||
import org.springframework.data.domain.PageRequest;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.domain.Sort;
|
||||
import org.springframework.data.domain.jaxb.SpringDataJaxb.OrderDto;
|
||||
import org.springframework.data.domain.jaxb.SpringDataJaxb.PageRequestDto;
|
||||
import org.springframework.data.domain.jaxb.SpringDataJaxb.SortDto;
|
||||
|
||||
/**
|
||||
* {@link XmlAdapter} to convert {@link Pageable} instances int a {@link PageRequestDto} and vice versa.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
class PageableAdapter extends XmlAdapter<PageRequestDto, Pageable> {
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see javax.xml.bind.annotation.adapters.XmlAdapter#marshal(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public PageRequestDto marshal(Pageable request) throws Exception {
|
||||
|
||||
SortDto sortDto = SortAdapter.INSTANCE.marshal(request.getSort());
|
||||
|
||||
PageRequestDto dto = new PageRequestDto();
|
||||
dto.orders = sortDto == null ? Collections.<OrderDto> emptyList() : sortDto.orders;
|
||||
dto.page = request.getPageNumber();
|
||||
dto.size = request.getPageSize();
|
||||
|
||||
return dto;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see javax.xml.bind.annotation.adapters.XmlAdapter#unmarshal(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public Pageable unmarshal(PageRequestDto v) throws Exception {
|
||||
|
||||
if (v.orders.isEmpty()) {
|
||||
return new PageRequest(v.page, v.size);
|
||||
}
|
||||
|
||||
SortDto sortDto = new SortDto();
|
||||
sortDto.orders = v.orders;
|
||||
Sort sort = SortAdapter.INSTANCE.unmarshal(sortDto);
|
||||
|
||||
return new PageRequest(v.page, v.size, sort);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
package org.springframework.data.domain.jaxb;
|
||||
|
||||
import javax.xml.bind.annotation.adapters.XmlAdapter;
|
||||
|
||||
import org.springframework.data.domain.Sort;
|
||||
import org.springframework.data.domain.jaxb.SpringDataJaxb.SortDto;
|
||||
|
||||
/**
|
||||
* {@link XmlAdapter} to convert {@link Sort} instances into {@link SortDto} instances and vice versa.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public class SortAdapter extends XmlAdapter<SortDto, Sort> {
|
||||
|
||||
public static final SortAdapter INSTANCE = new SortAdapter();
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see javax.xml.bind.annotation.adapters.XmlAdapter#marshal(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public SortDto marshal(Sort source) throws Exception {
|
||||
|
||||
if (source == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
SortDto dto = new SortDto();
|
||||
dto.orders = SpringDataJaxb.marshal(source, OrderAdapter.INSTANCE);
|
||||
|
||||
return dto;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see javax.xml.bind.annotation.adapters.XmlAdapter#unmarshal(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public Sort unmarshal(SortDto source) throws Exception {
|
||||
return source == null ? null : new Sort(SpringDataJaxb.unmarshal(source.orders, OrderAdapter.INSTANCE));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,153 @@
|
||||
/*
|
||||
* Copyright 2012 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.domain.jaxb;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import javax.xml.bind.annotation.XmlAccessType;
|
||||
import javax.xml.bind.annotation.XmlAccessorType;
|
||||
import javax.xml.bind.annotation.XmlAnyElement;
|
||||
import javax.xml.bind.annotation.XmlAttribute;
|
||||
import javax.xml.bind.annotation.XmlElement;
|
||||
import javax.xml.bind.annotation.XmlElementWrapper;
|
||||
import javax.xml.bind.annotation.XmlRootElement;
|
||||
import javax.xml.bind.annotation.adapters.XmlAdapter;
|
||||
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.PageRequest;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.domain.Sort;
|
||||
import org.springframework.data.domain.Sort.Direction;
|
||||
import org.springframework.data.domain.Sort.Order;
|
||||
import org.springframework.hateoas.ResourceSupport;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Helper class containing utility methods to implement JAXB {@link XmlAdapter}s as well as the DTO types to be
|
||||
* marshalled by JAXB.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public class SpringDataJaxb {
|
||||
|
||||
public static final String NAMESPACE = "http://www.springframework.org/schema/data/jaxb";
|
||||
|
||||
/**
|
||||
* The DTO for {@link Pageable}s/{@link PageRequest}s.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
@XmlRootElement(name = "page-request", namespace = NAMESPACE)
|
||||
@XmlAccessorType(XmlAccessType.FIELD)
|
||||
public static class PageRequestDto {
|
||||
|
||||
@XmlAttribute
|
||||
int page, size;
|
||||
@XmlElement(name = "order", namespace = NAMESPACE)
|
||||
List<OrderDto> orders = new ArrayList<OrderDto>();
|
||||
}
|
||||
|
||||
/**
|
||||
* The DTO for {@link Sort}.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
@XmlRootElement(name = "sort", namespace = NAMESPACE)
|
||||
@XmlAccessorType(XmlAccessType.FIELD)
|
||||
public static class SortDto {
|
||||
|
||||
@XmlElement(name = "order", namespace = SpringDataJaxb.NAMESPACE)
|
||||
List<OrderDto> orders = new ArrayList<OrderDto>();
|
||||
}
|
||||
|
||||
/**
|
||||
* The DTO for {@link Order}.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
@XmlRootElement(name = "order", namespace = NAMESPACE)
|
||||
@XmlAccessorType(XmlAccessType.FIELD)
|
||||
public static class OrderDto {
|
||||
|
||||
@XmlAttribute
|
||||
String property;
|
||||
@XmlAttribute
|
||||
Direction direction;
|
||||
}
|
||||
|
||||
/**
|
||||
* The DTO for {@link Page}.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
@XmlRootElement(name = "page", namespace = NAMESPACE)
|
||||
@XmlAccessorType(XmlAccessType.FIELD)
|
||||
public static class PageDto extends ResourceSupport {
|
||||
|
||||
@XmlAnyElement
|
||||
@XmlElementWrapper(name = "content")
|
||||
List<Object> content;
|
||||
}
|
||||
|
||||
/**
|
||||
* Unmarshals each element of the given {@link Collection} using the given {@link XmlAdapter}.
|
||||
*
|
||||
* @param source
|
||||
* @param adapter must not be {@literal null}.
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
public static <T, S> List<T> unmarshal(Collection<S> source, XmlAdapter<S, T> adapter) throws Exception {
|
||||
|
||||
Assert.notNull(adapter);
|
||||
|
||||
if (source == null || source.isEmpty()) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
List<T> result = new ArrayList<T>(source.size());
|
||||
for (S element : source) {
|
||||
result.add(adapter.unmarshal(element));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Marshals each of the elements of the given {@link Iterable} using the given {@link XmlAdapter}.
|
||||
*
|
||||
* @param source
|
||||
* @param adapter must not be {@literal null}.
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
public static <T, S> List<S> marshal(Iterable<T> source, XmlAdapter<S, T> adapter) throws Exception {
|
||||
|
||||
Assert.notNull(adapter);
|
||||
|
||||
if (source == null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
List<S> result = new ArrayList<S>();
|
||||
for (T element : source) {
|
||||
result.add(adapter.marshal(element));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
/**
|
||||
* Central domain abstractions especially to be used in combination with the {@link org.springframework.data.repository.Repository} abstraction.
|
||||
*
|
||||
* @see org.springframework.data.repository.Repository
|
||||
*/
|
||||
@XmlSchema(xmlns = { @XmlNs(prefix = "sd", namespaceURI = org.springframework.data.domain.jaxb.SpringDataJaxb.NAMESPACE) })
|
||||
@XmlJavaTypeAdapters({
|
||||
@XmlJavaTypeAdapter(value = org.springframework.data.domain.jaxb.PageableAdapter.class, type = Pageable.class),
|
||||
@XmlJavaTypeAdapter(value = org.springframework.data.domain.jaxb.SortAdapter.class, type = Sort.class),
|
||||
@XmlJavaTypeAdapter(value = org.springframework.data.domain.jaxb.PageAdapter.class, type = Page.class) })
|
||||
package org.springframework.data.domain.jaxb;
|
||||
|
||||
import javax.xml.bind.annotation.XmlNs;
|
||||
import javax.xml.bind.annotation.XmlSchema;
|
||||
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
|
||||
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapters;
|
||||
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.domain.Sort;
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
/**
|
||||
* Central domain abstractions especially to be used in combination with the {@link org.springframework.data.repository.Repository} abstraction.
|
||||
*
|
||||
* @see org.springframework.data.repository.Repository
|
||||
*/
|
||||
package org.springframework.data.domain;
|
||||
|
||||
@@ -0,0 +1,93 @@
|
||||
/*
|
||||
* Copyright 2012 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.history;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
|
||||
import org.joda.time.DateTime;
|
||||
import org.springframework.data.util.AnnotationDetectionFieldCallback;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
|
||||
/**
|
||||
* A {@link RevisionMetadata} implementation that inspects the given object for fields with the configured annotations
|
||||
* and returns the field's values on calls to {@link #getRevisionDate()} and {@link #getRevisionNumber()}.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public class AnnotationRevisionMetadata<N extends Number & Comparable<N>> implements RevisionMetadata<N> {
|
||||
|
||||
private final Object entity;
|
||||
private final N revisionNumber;
|
||||
private final DateTime revisionDate;
|
||||
|
||||
/**
|
||||
* Creates a new {@link AnnotationRevisionMetadata} inspecing the given entity for the given annotations. If no
|
||||
* annotations will be provided these values will not be looked up from the entity and return {@literal null}.
|
||||
*
|
||||
* @param entity must not be {@literal null}.
|
||||
* @param revisionNumberAnnotation
|
||||
* @param revisionTimeStampAnnotation
|
||||
*/
|
||||
public AnnotationRevisionMetadata(final Object entity, Class<? extends Annotation> revisionNumberAnnotation,
|
||||
Class<? extends Annotation> revisionTimeStampAnnotation) {
|
||||
|
||||
Assert.notNull(entity);
|
||||
this.entity = entity;
|
||||
|
||||
if (revisionNumberAnnotation != null) {
|
||||
AnnotationDetectionFieldCallback numberCallback = new AnnotationDetectionFieldCallback(revisionNumberAnnotation);
|
||||
ReflectionUtils.doWithFields(entity.getClass(), numberCallback);
|
||||
this.revisionNumber = numberCallback.getValue(entity);
|
||||
} else {
|
||||
this.revisionNumber = null;
|
||||
}
|
||||
|
||||
if (revisionTimeStampAnnotation != null) {
|
||||
AnnotationDetectionFieldCallback revisionCallback = new AnnotationDetectionFieldCallback(
|
||||
revisionTimeStampAnnotation);
|
||||
ReflectionUtils.doWithFields(entity.getClass(), revisionCallback);
|
||||
this.revisionDate = new DateTime(revisionCallback.getValue(entity));
|
||||
} else {
|
||||
this.revisionDate = null;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.repository.history.RevisionMetadata#getRevisionNumber()
|
||||
*/
|
||||
public N getRevisionNumber() {
|
||||
return revisionNumber;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.repository.history.RevisionMetadata#getRevisionDate()
|
||||
*/
|
||||
public DateTime getRevisionDate() {
|
||||
return revisionDate;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.repository.history.RevisionMetadata#getDelegate()
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> T getDelegate() {
|
||||
return (T) entity;
|
||||
}
|
||||
}
|
||||
132
src/main/java/org/springframework/data/history/Revision.java
Executable file
132
src/main/java/org/springframework/data/history/Revision.java
Executable file
@@ -0,0 +1,132 @@
|
||||
/*
|
||||
* Copyright 2012 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.history;
|
||||
|
||||
import org.joda.time.DateTime;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Wrapper to contain {@link RevisionMetadata} as well as the revisioned entity.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
* @author Philipp Huegelmeyer
|
||||
*/
|
||||
public final class Revision<N extends Number & Comparable<N>, T> implements Comparable<Revision<N, ?>> {
|
||||
|
||||
private final RevisionMetadata<N> metadata;
|
||||
private final T entity;
|
||||
|
||||
/**
|
||||
* Creates a new {@link Revision} consisting of the given {@link RevisionMetadata} and entity.
|
||||
*
|
||||
* @param metadata must not be {@literal null}.
|
||||
* @param entity must not be {@literal null}.
|
||||
*/
|
||||
public Revision(RevisionMetadata<N> metadata, T entity) {
|
||||
|
||||
Assert.notNull(metadata);
|
||||
Assert.notNull(entity);
|
||||
|
||||
this.metadata = metadata;
|
||||
this.entity = entity;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the revision number of the revision.
|
||||
*
|
||||
* @return the revision number.
|
||||
*/
|
||||
public N getRevisionNumber() {
|
||||
return metadata.getRevisionNumber();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the revision date of the revision.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public DateTime getRevisionDate() {
|
||||
return metadata.getRevisionDate();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the underlying entity.
|
||||
*
|
||||
* @return the entity
|
||||
*/
|
||||
public T getEntity() {
|
||||
return entity;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link RevisionMetadata} for the current {@link Revision}.
|
||||
*
|
||||
* @return the metadata
|
||||
*/
|
||||
public RevisionMetadata<N> getMetadata() {
|
||||
return metadata;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see java.lang.Comparable#compareTo(java.lang.Object)
|
||||
*/
|
||||
public int compareTo(Revision<N, ?> that) {
|
||||
return getRevisionNumber().compareTo(that.getRevisionNumber());
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see java.lang.Object#equals(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public boolean equals(Object obj) {
|
||||
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!(obj instanceof Revision)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Revision<N, T> that = (Revision<N, T>) obj;
|
||||
boolean sameRevisionNumber = this.metadata.getRevisionNumber().equals(that.metadata.getRevisionNumber());
|
||||
return !sameRevisionNumber ? false : this.entity.equals(that.entity);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see java.lang.Object#hashCode()
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
|
||||
int result = 17;
|
||||
result += 31 * metadata.hashCode();
|
||||
result += 31 * entity.hashCode();
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see java.lang.Object#toString()
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format("Revision %s of entity %s - Revision metadata %s", getRevisionNumber(), entity, metadata);
|
||||
}
|
||||
}
|
||||
48
src/main/java/org/springframework/data/history/RevisionMetadata.java
Executable file
48
src/main/java/org/springframework/data/history/RevisionMetadata.java
Executable file
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright 2012 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.history;
|
||||
|
||||
import org.joda.time.DateTime;
|
||||
|
||||
/**
|
||||
* Metadata about a revision.
|
||||
*
|
||||
* @author Philipp Huegelmeyer
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public interface RevisionMetadata<N extends Number & Comparable<N>> {
|
||||
|
||||
/**
|
||||
* Returns the revision number of the revision.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
N getRevisionNumber();
|
||||
|
||||
/**
|
||||
* Returns the date of the revision.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
DateTime getRevisionDate();
|
||||
|
||||
/**
|
||||
* Returns the underlying revision metadata which might provider more detailed implementation specific information.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
<T> T getDelegate();
|
||||
}
|
||||
102
src/main/java/org/springframework/data/history/Revisions.java
Normal file
102
src/main/java/org/springframework/data/history/Revisions.java
Normal file
@@ -0,0 +1,102 @@
|
||||
/*
|
||||
* Copyright 2012 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.history;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Simple wrapper class for a {@link List} of {@link Revisions} allowing to canonically access the latest revision.
|
||||
* Allows iterating over the underlying {@link Revisions} starting with older revisions.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public class Revisions<N extends Number & Comparable<N>, T> implements Iterable<Revision<N, T>> {
|
||||
|
||||
private final List<Revision<N, T>> revisions;
|
||||
private final boolean latestLast;
|
||||
|
||||
/**
|
||||
* Creates a new {@link Revisions} instance containing the given revisions. Will make sure they are ordered
|
||||
* ascendingly.
|
||||
*
|
||||
* @param revisions must not be {@literal null}.
|
||||
*/
|
||||
public Revisions(List<? extends Revision<N, T>> revisions) {
|
||||
this(revisions, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link Revisions} instance using the given revisions.
|
||||
*
|
||||
* @param revisions must not be {@literal null}.
|
||||
* @param latestLast
|
||||
*/
|
||||
private Revisions(List<? extends Revision<N, T>> revisions, boolean latestLast) {
|
||||
|
||||
Assert.notNull(revisions);
|
||||
this.revisions = new ArrayList<Revision<N, T>>(revisions);
|
||||
this.latestLast = latestLast;
|
||||
|
||||
Collections.sort(this.revisions);
|
||||
|
||||
if (!latestLast) {
|
||||
Collections.reverse(this.revisions);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the latest revision of the revisions backing the wrapper independently of the order.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public Revision<N, T> getLatestRevision() {
|
||||
int index = latestLast ? revisions.size() - 1 : 0;
|
||||
return revisions.get(index);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverses the current {@link Revisions}. By default this will return the revisions with the latest revision first.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public Revisions<N, T> reverse() {
|
||||
List<Revision<N, T>> result = new ArrayList<Revision<N, T>>(revisions);
|
||||
Collections.reverse(result);
|
||||
return new Revisions<N, T>(result, !latestLast);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see java.lang.Iterable#iterator()
|
||||
*/
|
||||
public Iterator<Revision<N, T>> iterator() {
|
||||
return revisions.iterator();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the content of the {@link Revisions} instance.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public List<Revision<N, T>> getContent() {
|
||||
return Collections.unmodifiableList(revisions);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
/**
|
||||
* Basic interfaces and value objects for historiography API.
|
||||
*/
|
||||
package org.springframework.data.history;
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright (c) 2011 by the original author(s).
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.data.mapping;
|
||||
|
||||
/**
|
||||
* Value object to capture {@link Association}s.
|
||||
*
|
||||
* @param the {@link PersistentProperty}s the association connects.
|
||||
* @author Jon Brisbin <jbrisbin@vmware.com>
|
||||
*/
|
||||
public class Association<P extends PersistentProperty<P>> {
|
||||
|
||||
private final P inverse;
|
||||
private final P obverse;
|
||||
|
||||
/**
|
||||
* Creates a new {@link Association} between the two given {@link PersistentProperty}s.
|
||||
*
|
||||
* @param inverse
|
||||
* @param obverse
|
||||
*/
|
||||
public Association(P inverse, P obverse) {
|
||||
this.inverse = inverse;
|
||||
this.obverse = obverse;
|
||||
}
|
||||
|
||||
public P getInverse() {
|
||||
return inverse;
|
||||
}
|
||||
|
||||
public P getObverse() {
|
||||
return obverse;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Copyright (c) 2011 by the original author(s).
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.data.mapping;
|
||||
|
||||
/**
|
||||
* Callback interface to implement functionality to be applied to a collection of {@link Association}s.
|
||||
*
|
||||
* @author Jon Brisbin <jbrisbin@vmware.com>
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public interface AssociationHandler<P extends PersistentProperty<P>> {
|
||||
|
||||
/**
|
||||
* Processes the given {@link Association}.
|
||||
*
|
||||
* @param association
|
||||
*/
|
||||
void doWithAssociation(Association<P> association);
|
||||
}
|
||||
@@ -0,0 +1,149 @@
|
||||
/*
|
||||
* Copyright 2011-2012 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.mapping;
|
||||
|
||||
import org.springframework.data.convert.EntityInstantiator;
|
||||
import org.springframework.data.util.TypeInformation;
|
||||
|
||||
/**
|
||||
* Represents a persistent entity.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
* @author Graeme Rocher
|
||||
* @author Jon Brisbin
|
||||
* @author Patryk Wasik
|
||||
*/
|
||||
public interface PersistentEntity<T, P extends PersistentProperty<P>> {
|
||||
|
||||
/**
|
||||
* The entity name including any package prefix.
|
||||
*
|
||||
* @return must never return {@literal null}
|
||||
*/
|
||||
String getName();
|
||||
|
||||
/**
|
||||
* Returns the {@link PreferredConstructor} to be used to instantiate objects of this {@link PersistentEntity}.
|
||||
*
|
||||
* @return {@literal null} in case no suitable constructor for automatic construction can be found. This usually
|
||||
* indicates that the instantiation of the object of tthat persistent entity is done through either a customer
|
||||
* {@link EntityInstantiator} or handled by custom conversion mechanisms entirely.
|
||||
*/
|
||||
PreferredConstructor<T, P> getPersistenceConstructor();
|
||||
|
||||
/**
|
||||
* Returns whether the given {@link PersistentProperty} is referred to by a constructor argument of the
|
||||
* {@link PersistentEntity}.
|
||||
*
|
||||
* @param property
|
||||
* @return true if the given {@link PersistentProperty} is referred to by a constructor argument or {@literal false}
|
||||
* if not or {@literal null}.
|
||||
*/
|
||||
boolean isConstructorArgument(PersistentProperty<?> property);
|
||||
|
||||
/**
|
||||
* Returns whether the given {@link PersistentProperty} is the id property of the entity.
|
||||
*
|
||||
* @param property
|
||||
* @return
|
||||
*/
|
||||
boolean isIdProperty(PersistentProperty<?> property);
|
||||
|
||||
/**
|
||||
* Returns whether the given {@link PersistentProperty} is the version property of the entity.
|
||||
*
|
||||
* @param property
|
||||
* @return
|
||||
*/
|
||||
boolean isVersionProperty(PersistentProperty<?> property);
|
||||
|
||||
/**
|
||||
* Returns the id property of the {@link PersistentEntity}. Can be {@literal null} in case this is an entity
|
||||
* completely handled by a custom conversion.
|
||||
*
|
||||
* @return the id property of the {@link PersistentEntity}.
|
||||
*/
|
||||
P getIdProperty();
|
||||
|
||||
/**
|
||||
* Returns the version property of the {@link PersistentEntity}. Can be {@literal null} in case no version property is
|
||||
* available on the entity.
|
||||
*
|
||||
* @return the version property of the {@link PersistentEntity}.
|
||||
*/
|
||||
P getVersionProperty();
|
||||
|
||||
/**
|
||||
* Obtains a {@link PersistentProperty} instance by name.
|
||||
*
|
||||
* @param name The name of the property
|
||||
* @return the {@link PersistentProperty} or {@literal null} if it doesn't exist.
|
||||
*/
|
||||
P getPersistentProperty(String name);
|
||||
|
||||
/**
|
||||
* Returns whether the {@link PersistentEntity} has an id property. If this call returns {@literal true},
|
||||
* {@link #getIdProperty()} will return a non-{@literal null} value.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
boolean hasIdProperty();
|
||||
|
||||
/**
|
||||
* Returns whether the {@link PersistentEntity} has a version property. If this call returns {@literal true},
|
||||
* {@link #getVersionProperty()} will return a non-{@literal null} value.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
boolean hasVersionProperty();
|
||||
|
||||
/**
|
||||
* Returns the resolved Java type of this entity.
|
||||
*
|
||||
* @return The underlying Java class for this entity
|
||||
*/
|
||||
Class<T> getType();
|
||||
|
||||
/**
|
||||
* Returns the alias to be used when storing type information. Might be {@literal null} to indicate that there was no
|
||||
* alias defined through the mapping metadata.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
Object getTypeAlias();
|
||||
|
||||
/**
|
||||
* Returns the {@link TypeInformation} backing this {@link PersistentEntity}.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
TypeInformation<T> getTypeInformation();
|
||||
|
||||
/**
|
||||
* Applies the given {@link PropertyHandler} to all {@link PersistentProperty}s contained in this
|
||||
* {@link PersistentEntity}.
|
||||
*
|
||||
* @param handler must not be {@literal null}.
|
||||
*/
|
||||
void doWithProperties(PropertyHandler<P> handler);
|
||||
|
||||
/**
|
||||
* Applies the given {@link AssociationHandler} to all {@link Association} contained in this {@link PersistentEntity}.
|
||||
*
|
||||
* @param handler must not be {@literal null}.
|
||||
*/
|
||||
void doWithAssociations(AssociationHandler<P> handler);
|
||||
}
|
||||
@@ -0,0 +1,174 @@
|
||||
/*
|
||||
* Copyright 2011-2012 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.mapping;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.data.util.TypeInformation;
|
||||
|
||||
/**
|
||||
* @author Graeme Rocher
|
||||
* @author Jon Brisbin
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public interface PersistentProperty<P extends PersistentProperty<P>> {
|
||||
|
||||
PersistentEntity<?, P> getOwner();
|
||||
|
||||
/**
|
||||
* The name of the property
|
||||
*
|
||||
* @return The property name
|
||||
*/
|
||||
String getName();
|
||||
|
||||
/**
|
||||
* The type of the property
|
||||
*
|
||||
* @return The property type
|
||||
*/
|
||||
Class<?> getType();
|
||||
|
||||
/**
|
||||
* Returns the {@link TypeInformation} of the property.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
TypeInformation<?> getTypeInformation();
|
||||
|
||||
/**
|
||||
* Returns the {@link TypeInformation} if the property references a {@link PersistentEntity}. Will return
|
||||
* {@literal null} in case it refers to a simple type. Will return {@link Collection}'s component type or the
|
||||
* {@link Map}'s value type transparently.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
Iterable<? extends TypeInformation<?>> getPersistentEntityType();
|
||||
|
||||
/**
|
||||
* Returns the getter method to access the property value if available. Might return {@literal null} in case there is
|
||||
* no getter method with a return type assignable to the actual property's type.
|
||||
*
|
||||
* @return the getter method to access the property value if available, otherwise {@literal null}.
|
||||
*/
|
||||
Method getGetter();
|
||||
|
||||
/**
|
||||
* Returns the setter method to set a property value. Might return {@literal null} in case there is no setter
|
||||
* available.
|
||||
*
|
||||
* @returnthe setter method to set a property value if available, otherwise {@literal null}.
|
||||
*/
|
||||
Method getSetter();
|
||||
|
||||
Field getField();
|
||||
|
||||
String getSpelExpression();
|
||||
|
||||
Association<P> getAssociation();
|
||||
|
||||
/**
|
||||
* Returns whether the type of the {@link PersistentProperty} is actually to be regarded as {@link PersistentEntity}
|
||||
* in turn.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
boolean isEntity();
|
||||
|
||||
/**
|
||||
* Returns whether the property is a <em>potential</em> identifier property of the owning {@link PersistentEntity}.
|
||||
* This method is mainly used by {@link PersistentEntity} implementation to discover id property candidates on
|
||||
* {@link PersistentEntity} creation you should rather call {@link PersistentEntity#isIdProperty(PersistentProperty)}
|
||||
* to determine whether the current property is the id property of that {@link PersistentEntity} under consideration.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
boolean isIdProperty();
|
||||
|
||||
/**
|
||||
* Returns whether the current property is a <em>potential</em> version property of the owning
|
||||
* {@link PersistentEntity}. This method is mainly used by {@link PersistentEntity} implementation to discover version
|
||||
* property candidates on {@link PersistentEntity} creation you should rather call
|
||||
* {@link PersistentEntity#isVersionProperty(PersistentProperty)} to determine whether the current property is the
|
||||
* version property of that {@link PersistentEntity} under consideration.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
boolean isVersionProperty();
|
||||
|
||||
/**
|
||||
* Returns whether the property is a {@link Collection}, {@link Iterable} or an array.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
boolean isCollectionLike();
|
||||
|
||||
/**
|
||||
* Returns whether the property is a {@link Map}.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
boolean isMap();
|
||||
|
||||
/**
|
||||
* Returns whether the property is an array.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
boolean isArray();
|
||||
|
||||
/**
|
||||
* Returns whether the property is transient.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
boolean isTransient();
|
||||
|
||||
boolean shallBePersisted();
|
||||
|
||||
/**
|
||||
* Returns whether the property is an {@link Association}.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
boolean isAssociation();
|
||||
|
||||
/**
|
||||
* Returns the component type of the type if it is a {@link java.util.Collection}. Will return the type of the key if
|
||||
* the property is a {@link java.util.Map}.
|
||||
*
|
||||
* @return the component type, the map's key type or {@literal null} if neither {@link java.util.Collection} nor
|
||||
* {@link java.util.Map}.
|
||||
*/
|
||||
Class<?> getComponentType();
|
||||
|
||||
/**
|
||||
* Returns the raw type as it's pulled from from the reflected property.
|
||||
*
|
||||
* @return the raw type of the property.
|
||||
*/
|
||||
Class<?> getRawType();
|
||||
|
||||
/**
|
||||
* Returns the type of the values if the property is a {@link java.util.Map}.
|
||||
*
|
||||
* @return the map's value type or {@literal null} if no {@link java.util.Map}
|
||||
*/
|
||||
Class<?> getMapValueType();
|
||||
}
|
||||
@@ -0,0 +1,299 @@
|
||||
/*
|
||||
* Copyright 2011-2013 by the original author(s).
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.mapping;
|
||||
|
||||
import static org.springframework.util.ObjectUtils.*;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.data.annotation.PersistenceConstructor;
|
||||
import org.springframework.data.util.TypeInformation;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Value object to encapsulate the constructor to be used when mapping persistent data to objects.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
* @author Jon Brisbin
|
||||
*/
|
||||
public class PreferredConstructor<T, P extends PersistentProperty<P>> {
|
||||
|
||||
private final Constructor<T> constructor;
|
||||
private final List<Parameter<Object, P>> parameters;
|
||||
|
||||
/**
|
||||
* Creates a new {@link PreferredConstructor} from the given {@link Constructor} and {@link Parameter}s.
|
||||
*
|
||||
* @param constructor
|
||||
* @param parameters
|
||||
*/
|
||||
public PreferredConstructor(Constructor<T> constructor, Parameter<Object, P>... parameters) {
|
||||
|
||||
Assert.notNull(constructor);
|
||||
Assert.notNull(parameters);
|
||||
|
||||
ReflectionUtils.makeAccessible(constructor);
|
||||
this.constructor = constructor;
|
||||
this.parameters = Arrays.asList(parameters);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the underlying {@link Constructor}.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public Constructor<T> getConstructor() {
|
||||
return constructor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link Parameter}s of the constructor.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public Iterable<Parameter<Object, P>> getParameters() {
|
||||
return parameters;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the constructor has {@link Parameter}s.
|
||||
*
|
||||
* @see #isNoArgConstructor()
|
||||
* @return
|
||||
*/
|
||||
public boolean hasParameters() {
|
||||
return !parameters.isEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the constructor does not have any arguments.
|
||||
*
|
||||
* @see #hasParameters()
|
||||
* @return
|
||||
*/
|
||||
public boolean isNoArgConstructor() {
|
||||
return parameters.isEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the constructor was explicitly selected (by {@link PersistenceConstructor}).
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public boolean isExplicitlyAnnotated() {
|
||||
return constructor.isAnnotationPresent(PersistenceConstructor.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the given {@link PersistentProperty} is referenced in a constructor argument of the
|
||||
* {@link PersistentEntity} backing this {@link PreferredConstructor}.
|
||||
*
|
||||
* @param property must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public boolean isConstructorParameter(PersistentProperty<?> property) {
|
||||
|
||||
Assert.notNull(property);
|
||||
|
||||
for (Parameter<?, P> parameter : parameters) {
|
||||
if (parameter.maps(property)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the given {@link Parameter} is one referring to an enclosing class. That is in case the class this
|
||||
* {@link PreferredConstructor} belongs to is a member class actually. If that's the case the compiler creates a first
|
||||
* constructor argument of the enclosing class type.
|
||||
*
|
||||
* @param parameter must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public boolean isEnclosingClassParameter(Parameter<?, P> parameter) {
|
||||
|
||||
Assert.notNull(parameter);
|
||||
|
||||
if (parameters.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return parameters.get(0).equals(parameter) && parameter.isEnclosingClassParameter();
|
||||
}
|
||||
|
||||
/**
|
||||
* Value object to represent constructor parameters.
|
||||
*
|
||||
* @param <T> the type of the parameter
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public static class Parameter<T, P extends PersistentProperty<P>> {
|
||||
|
||||
private final String name;
|
||||
private final TypeInformation<T> type;
|
||||
private final String key;
|
||||
private final PersistentEntity<T, P> entity;
|
||||
|
||||
private Boolean enclosingClassCache;
|
||||
|
||||
/**
|
||||
* Creates a new {@link Parameter} with the given name, {@link TypeInformation} as well as an array of
|
||||
* {@link Annotation}s. Will insprect the annotations for an {@link Value} annotation to lookup a key or an SpEL
|
||||
* expression to be evaluated.
|
||||
*
|
||||
* @param name the name of the parameter, can be {@literal null}
|
||||
* @param type must not be {@literal null}
|
||||
* @param annotations must not be {@literal null} but can be empty
|
||||
* @param entity can be {@literal null}.
|
||||
*/
|
||||
public Parameter(String name, TypeInformation<T> type, Annotation[] annotations, PersistentEntity<T, P> entity) {
|
||||
|
||||
Assert.notNull(type);
|
||||
Assert.notNull(annotations);
|
||||
|
||||
this.name = name;
|
||||
this.type = type;
|
||||
this.key = getValue(annotations);
|
||||
this.entity = entity;
|
||||
}
|
||||
|
||||
private String getValue(Annotation[] annotations) {
|
||||
for (Annotation anno : annotations) {
|
||||
if (anno.annotationType() == Value.class) {
|
||||
return ((Value) anno).value();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of the parameter or {@literal null} if none was given.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link TypeInformation} of the parameter.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public TypeInformation<T> getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the raw resolved type of the parameter.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public Class<T> getRawType() {
|
||||
return type.getType();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the key to be used when looking up a source data structure to populate the actual parameter value.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public String getSpelExpression() {
|
||||
return key;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the constructor parameter is equipped with a SpEL expression.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public boolean hasSpelExpression() {
|
||||
return StringUtils.hasText(getSpelExpression());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the {@link Parameter} maps the given {@link PersistentProperty}.
|
||||
*
|
||||
* @param property
|
||||
* @return
|
||||
*/
|
||||
boolean maps(PersistentProperty<?> property) {
|
||||
|
||||
P referencedProperty = entity == null ? null : entity.getPersistentProperty(name);
|
||||
return property == null ? false : property.equals(referencedProperty);
|
||||
}
|
||||
|
||||
private boolean isEnclosingClassParameter() {
|
||||
|
||||
if (enclosingClassCache == null) {
|
||||
Class<T> owningType = entity.getType();
|
||||
this.enclosingClassCache = owningType.isMemberClass() && type.getType().equals(owningType.getEnclosingClass());
|
||||
}
|
||||
|
||||
return enclosingClassCache;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see java.lang.Object#equals(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!(obj instanceof Parameter)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Parameter<?, ?> that = (Parameter<?, ?>) obj;
|
||||
|
||||
boolean nameEquals = this.name == null ? that.name == null : this.name.equals(that.name);
|
||||
boolean keyEquals = this.key == null ? that.key == null : this.key.equals(that.key);
|
||||
boolean typeEquals = nullSafeEquals(this.type, that.type);
|
||||
boolean entityEquals = this.entity == null ? that.entity == null : this.entity.equals(that.entity);
|
||||
|
||||
return nameEquals && keyEquals && typeEquals && entityEquals;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see java.lang.Object#hashCode()
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
|
||||
int result = 17;
|
||||
|
||||
result += 31 * nullSafeHashCode(this.name);
|
||||
result += 31 * nullSafeHashCode(this.key);
|
||||
result += 31 * nullSafeHashCode(this.type);
|
||||
result += 31 * nullSafeHashCode(this.entity);
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Copyright (c) 2011 by the original author(s).
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.mapping;
|
||||
|
||||
/**
|
||||
* Callback interface to do something with all plain {@link PersistentProperty} instances <em>except</em> associations
|
||||
* and transient properties.
|
||||
*
|
||||
* @author Jon Brisbin <jbrisbin@vmware.com>
|
||||
*/
|
||||
public interface PropertyHandler<P extends PersistentProperty<P>> {
|
||||
|
||||
void doWithPersistentProperty(P persistentProperty);
|
||||
}
|
||||
358
src/main/java/org/springframework/data/mapping/PropertyPath.java
Normal file
358
src/main/java/org/springframework/data/mapping/PropertyPath.java
Normal file
@@ -0,0 +1,358 @@
|
||||
/*
|
||||
* Copyright 2011-2012 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.mapping;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import org.springframework.data.util.ClassTypeInformation;
|
||||
import org.springframework.data.util.TypeInformation;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Abstraction of a {@link PropertyPath} of a domain class.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public class PropertyPath implements Iterable<PropertyPath> {
|
||||
|
||||
private static final String DELIMITERS = "_\\.";
|
||||
private static final String ALL_UPPERCASE = "[A-Z0-9._$]+";
|
||||
private static final Pattern SPLITTER = Pattern.compile("(?:[%s]?([%s]*?[^%s]+))".replaceAll("%s", DELIMITERS));
|
||||
|
||||
private final TypeInformation<?> owningType;
|
||||
private final String name;
|
||||
private final TypeInformation<?> type;
|
||||
private final boolean isCollection;
|
||||
|
||||
private PropertyPath next;
|
||||
|
||||
/**
|
||||
* Creates a leaf {@link PropertyPath} (no nested ones) with the given name inside the given owning type.
|
||||
*
|
||||
* @param name must not be {@literal null} or empty.
|
||||
* @param owningType must not be {@literal null}.
|
||||
*/
|
||||
PropertyPath(String name, Class<?> owningType) {
|
||||
|
||||
this(name, ClassTypeInformation.from(owningType), null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a leaf {@link PropertyPath} (no nested ones with the given name and owning type.
|
||||
*
|
||||
* @param name must not be {@literal null} or empty.
|
||||
* @param owningType must not be {@literal null}.
|
||||
* @param base the {@link PropertyPath} previously found.
|
||||
*/
|
||||
PropertyPath(String name, TypeInformation<?> owningType, PropertyPath base) {
|
||||
|
||||
Assert.hasText(name);
|
||||
Assert.notNull(owningType);
|
||||
|
||||
String propertyName = name.matches(ALL_UPPERCASE) ? name : StringUtils.uncapitalize(name);
|
||||
TypeInformation<?> type = owningType.getProperty(propertyName);
|
||||
|
||||
if (type == null) {
|
||||
throw new PropertyReferenceException(propertyName, owningType, base);
|
||||
}
|
||||
|
||||
this.owningType = owningType;
|
||||
this.isCollection = type.isCollectionLike();
|
||||
this.type = type.getActualType();
|
||||
this.name = propertyName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the owning type of the {@link PropertyPath}.
|
||||
*
|
||||
* @return the owningType will never be {@literal null}.
|
||||
*/
|
||||
public TypeInformation<?> getOwningType() {
|
||||
return owningType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of the {@link PropertyPath}.
|
||||
*
|
||||
* @return the name will never be {@literal null}.
|
||||
*/
|
||||
public String getSegment() {
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the leaf property of the {@link PropertyPath}.
|
||||
*
|
||||
* @return will never be {@literal null}.
|
||||
*/
|
||||
public PropertyPath getLeafProperty() {
|
||||
|
||||
PropertyPath result = this;
|
||||
|
||||
while (result.hasNext()) {
|
||||
result = result.next();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the type of the property will return the plain resolved type for simple properties, the component type for
|
||||
* any {@link Iterable} or the value type of a {@link java.util.Map} if the property is one.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public Class<?> getType() {
|
||||
return this.type.getType();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the next nested {@link PropertyPath}.
|
||||
*
|
||||
* @return the next nested {@link PropertyPath} or {@literal null} if no nested {@link PropertyPath} available.
|
||||
* @see #hasNext()
|
||||
*/
|
||||
public PropertyPath next() {
|
||||
|
||||
return next;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether there is a nested {@link PropertyPath}. If this returns {@literal true} you can expect
|
||||
* {@link #next()} to return a non- {@literal null} value.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public boolean hasNext() {
|
||||
|
||||
return next != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link PropertyPath} in dot notation.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public String toDotPath() {
|
||||
|
||||
if (hasNext()) {
|
||||
return getSegment() + "." + next().toDotPath();
|
||||
}
|
||||
|
||||
return getSegment();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the {@link PropertyPath} is actually a collection.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public boolean isCollection() {
|
||||
|
||||
return isCollection;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see java.lang.Object#equals(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (obj == null || !getClass().equals(obj.getClass())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
PropertyPath that = (PropertyPath) obj;
|
||||
|
||||
return this.name.equals(that.name) && this.type.equals(that.type)
|
||||
&& ObjectUtils.nullSafeEquals(this.next, that.next);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see java.lang.Object#hashCode()
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
|
||||
int result = 17;
|
||||
|
||||
result += 31 * name.hashCode();
|
||||
result += 31 * type.hashCode();
|
||||
result += 31 * (next == null ? 0 : next.hashCode());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see java.lang.Iterable#iterator()
|
||||
*/
|
||||
public Iterator<PropertyPath> iterator() {
|
||||
return new Iterator<PropertyPath>() {
|
||||
|
||||
private PropertyPath current = PropertyPath.this;
|
||||
|
||||
public boolean hasNext() {
|
||||
return current != null;
|
||||
}
|
||||
|
||||
public PropertyPath next() {
|
||||
PropertyPath result = current;
|
||||
this.current = current.next();
|
||||
return result;
|
||||
}
|
||||
|
||||
public void remove() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts the {@link PropertyPath} chain from the given source {@link String} and type.
|
||||
*
|
||||
* @param source
|
||||
* @param type
|
||||
* @return
|
||||
*/
|
||||
public static PropertyPath from(String source, Class<?> type) {
|
||||
|
||||
return from(source, ClassTypeInformation.from(type));
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts the {@link PropertyPath} chain from the given source {@link String} and {@link TypeInformation}.
|
||||
*
|
||||
* @param source must not be {@literal null}.
|
||||
* @param type
|
||||
* @return
|
||||
*/
|
||||
public static PropertyPath from(String source, TypeInformation<?> type) {
|
||||
|
||||
List<String> iteratorSource = new ArrayList<String>();
|
||||
Matcher matcher = SPLITTER.matcher("_" + source);
|
||||
|
||||
while (matcher.find()) {
|
||||
iteratorSource.add(matcher.group(1));
|
||||
}
|
||||
|
||||
Iterator<String> parts = iteratorSource.iterator();
|
||||
|
||||
PropertyPath result = null;
|
||||
PropertyPath current = null;
|
||||
|
||||
while (parts.hasNext()) {
|
||||
if (result == null) {
|
||||
result = create(parts.next(), type, null);
|
||||
current = result;
|
||||
} else {
|
||||
current = create(parts.next(), current);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link PropertyPath} as subordinary of the given {@link PropertyPath}.
|
||||
*
|
||||
* @param source
|
||||
* @param base
|
||||
* @return
|
||||
*/
|
||||
private static PropertyPath create(String source, PropertyPath base) {
|
||||
|
||||
PropertyPath propertyPath = create(source, base.type, base);
|
||||
base.next = propertyPath;
|
||||
return propertyPath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Factory method to create a new {@link PropertyPath} for the given {@link String} and owning type. It will inspect
|
||||
* the given source for camel-case parts and traverse the {@link String} along its parts starting with the entire one
|
||||
* and chewing off parts from the right side then. Whenever a valid property for the given class is found, the tail
|
||||
* will be traversed for subordinary properties of the just found one and so on.
|
||||
*
|
||||
* @param source
|
||||
* @param type
|
||||
* @return
|
||||
*/
|
||||
private static PropertyPath create(String source, TypeInformation<?> type, PropertyPath base) {
|
||||
|
||||
return create(source, type, "", base);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tries to look up a chain of {@link PropertyPath}s by trying the givne source first. If that fails it will split the
|
||||
* source apart at camel case borders (starting from the right side) and try to look up a {@link PropertyPath} from
|
||||
* the calculated head and recombined new tail and additional tail.
|
||||
*
|
||||
* @param source
|
||||
* @param type
|
||||
* @param addTail
|
||||
* @return
|
||||
*/
|
||||
private static PropertyPath create(String source, TypeInformation<?> type, String addTail, PropertyPath base) {
|
||||
|
||||
PropertyReferenceException exception = null;
|
||||
PropertyPath current = null;
|
||||
|
||||
try {
|
||||
|
||||
current = new PropertyPath(source, type, base);
|
||||
|
||||
if (StringUtils.hasText(addTail)) {
|
||||
current.next = create(addTail, current.type, current);
|
||||
}
|
||||
|
||||
return current;
|
||||
|
||||
} catch (PropertyReferenceException e) {
|
||||
|
||||
if (current != null) {
|
||||
throw e;
|
||||
}
|
||||
|
||||
exception = e;
|
||||
}
|
||||
|
||||
Pattern pattern = Pattern.compile("\\p{Lu}+\\p{Ll}*$");
|
||||
Matcher matcher = pattern.matcher(source);
|
||||
|
||||
if (matcher.find() && matcher.start() != 0) {
|
||||
|
||||
int position = matcher.start();
|
||||
String head = source.substring(0, position);
|
||||
String tail = source.substring(position);
|
||||
|
||||
return create(head, type, tail + addTail, base);
|
||||
}
|
||||
|
||||
throw exception;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
* Copyright 2012 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.mapping;
|
||||
|
||||
import org.springframework.data.util.TypeInformation;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Exception being thrown when creating {@link PropertyPath} instances.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public class PropertyReferenceException extends RuntimeException {
|
||||
|
||||
private static final long serialVersionUID = -5254424051438976570L;
|
||||
private static final String ERROR_TEMPLATE = "No property %s found for type %s";
|
||||
|
||||
private final String propertyName;
|
||||
private final TypeInformation<?> type;
|
||||
private final PropertyPath base;
|
||||
|
||||
/**
|
||||
* Creates a new {@link PropertyReferenceException}.
|
||||
*
|
||||
* @param propertyName the name of the property not found on the given type.
|
||||
* @param type the type the property could not be found on.
|
||||
* @param base the base {@link PropertyPath}.
|
||||
*/
|
||||
public PropertyReferenceException(String propertyName, TypeInformation<?> type, PropertyPath base) {
|
||||
|
||||
Assert.hasText(propertyName);
|
||||
Assert.notNull(type);
|
||||
|
||||
this.propertyName = propertyName;
|
||||
this.type = type;
|
||||
this.base = base;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of the property not found.
|
||||
*
|
||||
* @return will not be {@literal null} or empty.
|
||||
*/
|
||||
public String getPropertyName() {
|
||||
return propertyName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the type the property could not be found on.
|
||||
*
|
||||
* @return the type
|
||||
*/
|
||||
public TypeInformation<?> getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see java.lang.Throwable#getMessage()
|
||||
*/
|
||||
@Override
|
||||
public String getMessage() {
|
||||
return String.format(ERROR_TEMPLATE, propertyName, type.getType().getName());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link PropertyPath} which could be resolved so far.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public PropertyPath getBaseProperty() {
|
||||
return base;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,503 @@
|
||||
/*
|
||||
* Copyright 2011-2012 by the original author(s).
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.mapping.context;
|
||||
|
||||
import java.beans.BeanInfo;
|
||||
import java.beans.IntrospectionException;
|
||||
import java.beans.Introspector;
|
||||
import java.beans.PropertyDescriptor;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ApplicationContextAware;
|
||||
import org.springframework.context.ApplicationEventPublisher;
|
||||
import org.springframework.context.ApplicationEventPublisherAware;
|
||||
import org.springframework.context.ApplicationListener;
|
||||
import org.springframework.context.event.ContextRefreshedEvent;
|
||||
import org.springframework.data.mapping.PersistentEntity;
|
||||
import org.springframework.data.mapping.PersistentProperty;
|
||||
import org.springframework.data.mapping.PropertyPath;
|
||||
import org.springframework.data.mapping.model.MappingException;
|
||||
import org.springframework.data.mapping.model.MutablePersistentEntity;
|
||||
import org.springframework.data.mapping.model.SimpleTypeHolder;
|
||||
import org.springframework.data.util.ClassTypeInformation;
|
||||
import org.springframework.data.util.TypeInformation;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
import org.springframework.util.ReflectionUtils.FieldCallback;
|
||||
import org.springframework.util.ReflectionUtils.FieldFilter;
|
||||
|
||||
/**
|
||||
* Base class to build mapping metadata and thus create instances of {@link PersistentEntity} and
|
||||
* {@link PersistentProperty}.
|
||||
* <p>
|
||||
* The implementation uses a {@link ReentrantReadWriteLock} to make sure {@link PersistentEntity} are completely
|
||||
* populated before accessing them from outside.
|
||||
*
|
||||
* @param E the concrete {@link PersistentEntity} type the {@link MappingContext} implementation creates
|
||||
* @param P the concrete {@link PersistentProperty} type the {@link MappingContext} implementation creates
|
||||
* @author Jon Brisbin <jbrisbin@vmware.com>
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public abstract class AbstractMappingContext<E extends MutablePersistentEntity<?, P>, P extends PersistentProperty<P>>
|
||||
implements MappingContext<E, P>, ApplicationContextAware, ApplicationEventPublisherAware,
|
||||
ApplicationListener<ContextRefreshedEvent> {
|
||||
|
||||
private final ConcurrentMap<TypeInformation<?>, E> persistentEntities = new ConcurrentHashMap<TypeInformation<?>, E>();
|
||||
|
||||
private ApplicationContext applicationContext;
|
||||
private ApplicationEventPublisher applicationEventPublisher;
|
||||
|
||||
private Set<? extends Class<?>> initialEntitySet = new HashSet<Class<?>>();
|
||||
private boolean strict = false;
|
||||
private SimpleTypeHolder simpleTypeHolder = new SimpleTypeHolder();
|
||||
|
||||
private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
|
||||
private final Lock read = lock.readLock();
|
||||
private final Lock write = lock.writeLock();
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.context.ApplicationContextAware#setApplicationContext(org.springframework.context.ApplicationContext)
|
||||
*/
|
||||
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
|
||||
|
||||
this.applicationContext = applicationContext;
|
||||
|
||||
// Default publisher
|
||||
if (this.applicationEventPublisher == null) {
|
||||
this.applicationEventPublisher = applicationContext;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.context.ApplicationEventPublisherAware#setApplicationEventPublisher(org.springframework.context.ApplicationEventPublisher)
|
||||
*/
|
||||
public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
|
||||
this.applicationEventPublisher = applicationEventPublisher;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the {@link Set} of types to populate the context initially.
|
||||
*
|
||||
* @param initialEntitySet
|
||||
*/
|
||||
public void setInitialEntitySet(Set<? extends Class<?>> initialEntitySet) {
|
||||
this.initialEntitySet = initialEntitySet;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures whether the {@link MappingContext} is in strict mode which means, that it will throw
|
||||
* {@link MappingException}s in case one tries to lookup a {@link PersistentEntity} not already in the context. This
|
||||
* defaults to {@literal false} so that unknown types will be transparently added to the MappingContext if not known
|
||||
* in advance.
|
||||
*
|
||||
* @param strict
|
||||
*/
|
||||
public void setStrict(boolean strict) {
|
||||
this.strict = strict;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures the {@link SimpleTypeHolder} to be used by the {@link MappingContext}. Allows customization of what
|
||||
* types will be regarded as simple types and thus not recursively analysed. Setting this to {@literal null} will
|
||||
* reset the context to use the default {@link SimpleTypeHolder}.
|
||||
*
|
||||
* @param simpleTypes
|
||||
*/
|
||||
public void setSimpleTypeHolder(SimpleTypeHolder simpleTypes) {
|
||||
this.simpleTypeHolder = simpleTypes == null ? new SimpleTypeHolder() : simpleTypes;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.model.MappingContext#getPersistentEntities()
|
||||
*/
|
||||
public Collection<E> getPersistentEntities() {
|
||||
try {
|
||||
read.lock();
|
||||
return persistentEntities.values();
|
||||
} finally {
|
||||
read.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.model.MappingContext#getPersistentEntity(java.lang.Class)
|
||||
*/
|
||||
public E getPersistentEntity(Class<?> type) {
|
||||
Assert.notNull(type);
|
||||
return getPersistentEntity(ClassTypeInformation.from(type));
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.model.MappingContext#getPersistentEntity(org.springframework.data.util.TypeInformation)
|
||||
*/
|
||||
public E getPersistentEntity(TypeInformation<?> type) {
|
||||
|
||||
Assert.notNull(type);
|
||||
|
||||
try {
|
||||
read.lock();
|
||||
E entity = persistentEntities.get(type);
|
||||
|
||||
if (entity != null) {
|
||||
return entity;
|
||||
}
|
||||
|
||||
} finally {
|
||||
read.unlock();
|
||||
}
|
||||
|
||||
if (strict) {
|
||||
throw new MappingException("Unknown persistent entity " + type);
|
||||
}
|
||||
|
||||
if (!shouldCreatePersistentEntityFor(type)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return addPersistentEntity(type);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.context.MappingContext#getPersistentEntity(org.springframework.data.mapping.PersistentProperty)
|
||||
*/
|
||||
public E getPersistentEntity(P persistentProperty) {
|
||||
|
||||
if (persistentProperty == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
read.lock();
|
||||
return persistentEntities.get(persistentProperty.getTypeInformation());
|
||||
} finally {
|
||||
read.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.context.MappingContext#getPersistentPropertyPath(java.lang.Class, java.lang.String)
|
||||
*/
|
||||
public PersistentPropertyPath<P> getPersistentPropertyPath(PropertyPath propertyPath) {
|
||||
|
||||
List<P> result = new ArrayList<P>();
|
||||
E current = getPersistentEntity(propertyPath.getOwningType());
|
||||
|
||||
for (PropertyPath segment : propertyPath) {
|
||||
|
||||
P persistentProperty = current.getPersistentProperty(segment.getSegment());
|
||||
|
||||
if (persistentProperty == null) {
|
||||
throw new IllegalArgumentException(String.format("No property %s found on %s!", segment.getSegment(),
|
||||
current.getName()));
|
||||
}
|
||||
|
||||
result.add(persistentProperty);
|
||||
|
||||
if (segment.hasNext()) {
|
||||
current = getPersistentEntity(segment.getType());
|
||||
}
|
||||
}
|
||||
|
||||
return new DefaultPersistentPropertyPath<P>(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the given type to the {@link MappingContext}.
|
||||
*
|
||||
* @param type
|
||||
* @return
|
||||
*/
|
||||
protected E addPersistentEntity(Class<?> type) {
|
||||
return addPersistentEntity(ClassTypeInformation.from(type));
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the given {@link TypeInformation} to the {@link MappingContext}.
|
||||
*
|
||||
* @param typeInformation
|
||||
* @return
|
||||
*/
|
||||
protected E addPersistentEntity(TypeInformation<?> typeInformation) {
|
||||
|
||||
E persistentEntity = persistentEntities.get(typeInformation);
|
||||
|
||||
if (persistentEntity != null) {
|
||||
return persistentEntity;
|
||||
}
|
||||
|
||||
Class<?> type = typeInformation.getType();
|
||||
|
||||
try {
|
||||
|
||||
write.lock();
|
||||
|
||||
final E entity = createPersistentEntity(typeInformation);
|
||||
|
||||
// Eagerly cache the entity as we might have to find it during recursive lookups.
|
||||
persistentEntities.put(typeInformation, entity);
|
||||
|
||||
BeanInfo info = Introspector.getBeanInfo(type);
|
||||
|
||||
final Map<String, PropertyDescriptor> descriptors = new HashMap<String, PropertyDescriptor>();
|
||||
for (PropertyDescriptor descriptor : info.getPropertyDescriptors()) {
|
||||
descriptors.put(descriptor.getName(), descriptor);
|
||||
}
|
||||
|
||||
ReflectionUtils.doWithFields(type, new PersistentPropertyCreator(entity, descriptors),
|
||||
PersistentFieldFilter.INSTANCE);
|
||||
|
||||
try {
|
||||
entity.verify();
|
||||
} catch (MappingException e) {
|
||||
persistentEntities.remove(typeInformation);
|
||||
throw e;
|
||||
}
|
||||
|
||||
// Inform listeners
|
||||
if (null != applicationEventPublisher) {
|
||||
applicationEventPublisher.publishEvent(new MappingContextEvent<E, P>(this, entity));
|
||||
}
|
||||
|
||||
return entity;
|
||||
|
||||
} catch (IntrospectionException e) {
|
||||
throw new MappingException(e.getMessage(), e);
|
||||
} finally {
|
||||
write.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the concrete {@link PersistentEntity} instance.
|
||||
*
|
||||
* @param <T>
|
||||
* @param typeInformation
|
||||
* @return
|
||||
*/
|
||||
protected abstract <T> E createPersistentEntity(TypeInformation<T> typeInformation);
|
||||
|
||||
/**
|
||||
* Creates the concrete instance of {@link PersistentProperty}.
|
||||
*
|
||||
* @param field
|
||||
* @param descriptor
|
||||
* @param owner
|
||||
* @param simpleTypeHolder
|
||||
* @return
|
||||
*/
|
||||
protected abstract P createPersistentProperty(Field field, PropertyDescriptor descriptor, E owner,
|
||||
SimpleTypeHolder simpleTypeHolder);
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.context.ApplicationListener#onApplicationEvent(org.springframework.context.ApplicationEvent)
|
||||
*/
|
||||
public void onApplicationEvent(ContextRefreshedEvent event) {
|
||||
|
||||
if (!event.getApplicationContext().equals(applicationContext)) {
|
||||
return;
|
||||
}
|
||||
|
||||
initialize();
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the mapping context. Will add the types configured through {@link #setInitialEntitySet(Set)} to the
|
||||
* context.
|
||||
*/
|
||||
public void initialize() {
|
||||
|
||||
for (Class<?> initialEntity : initialEntitySet) {
|
||||
addPersistentEntity(initialEntity);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether a {@link PersistentEntity} instance should be created for the given {@link TypeInformation}. By
|
||||
* default this will reject this for all types considered simple, but it might be necessary to tweak that in case you
|
||||
* have registered custom converters for top level types (which renders them to be considered simple) but still need
|
||||
* meta-information about them.
|
||||
*
|
||||
* @param type will never be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
protected boolean shouldCreatePersistentEntityFor(TypeInformation<?> type) {
|
||||
return !simpleTypeHolder.isSimpleType(type.getType());
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link FieldCallback} to create {@link PersistentProperty} instances.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
private final class PersistentPropertyCreator implements FieldCallback {
|
||||
|
||||
private final E entity;
|
||||
private final Map<String, PropertyDescriptor> descriptors;
|
||||
|
||||
/**
|
||||
* Creates a new {@link PersistentPropertyCreator} for the given {@link PersistentEntity} and
|
||||
* {@link PropertyDescriptor}s.
|
||||
*
|
||||
* @param entity
|
||||
* @param descriptors
|
||||
*/
|
||||
private PersistentPropertyCreator(E entity, Map<String, PropertyDescriptor> descriptors) {
|
||||
this.entity = entity;
|
||||
this.descriptors = descriptors;
|
||||
}
|
||||
|
||||
public void doWith(Field field) {
|
||||
|
||||
PropertyDescriptor descriptor = descriptors.get(field.getName());
|
||||
|
||||
ReflectionUtils.makeAccessible(field);
|
||||
P property = createPersistentProperty(field, descriptor, entity, simpleTypeHolder);
|
||||
|
||||
if (property.isTransient()) {
|
||||
return;
|
||||
}
|
||||
|
||||
entity.addPersistentProperty(property);
|
||||
|
||||
if (property.isAssociation()) {
|
||||
entity.addAssociation(property.getAssociation());
|
||||
}
|
||||
|
||||
if (entity.getType().equals(property.getRawType())) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!property.isEntity()) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (TypeInformation<?> candidate : property.getPersistentEntityType()) {
|
||||
addPersistentEntity(candidate);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link FieldFilter} rejecting static fields as well as artifically introduced ones. See
|
||||
* {@link PersistentFieldFilter#UNMAPPED_FIELDS} for details.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
private static enum PersistentFieldFilter implements FieldFilter {
|
||||
|
||||
INSTANCE;
|
||||
|
||||
private static final Iterable<FieldMatch> UNMAPPED_FIELDS;
|
||||
|
||||
static {
|
||||
|
||||
Set<FieldMatch> matches = new HashSet<FieldMatch>();
|
||||
matches.add(new FieldMatch("class", null));
|
||||
matches.add(new FieldMatch("this\\$.*", null));
|
||||
matches.add(new FieldMatch("metaClass", "groovy.lang.MetaClass"));
|
||||
|
||||
UNMAPPED_FIELDS = Collections.unmodifiableCollection(matches);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.util.ReflectionUtils.FieldFilter#matches(java.lang.reflect.Field)
|
||||
*/
|
||||
public boolean matches(Field field) {
|
||||
|
||||
if (Modifier.isStatic(field.getModifiers())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (FieldMatch candidate : UNMAPPED_FIELDS) {
|
||||
if (candidate.matches(field)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Value object to help defining field eclusion based on name patterns and types.
|
||||
*
|
||||
* @since 1.4
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
static class FieldMatch {
|
||||
|
||||
private final String namePattern;
|
||||
private final String typeName;
|
||||
|
||||
/**
|
||||
* Creates a new {@link FieldMatch} for the given name pattern and type name. At least one of the paramters must not
|
||||
* be {@literal null}.
|
||||
*
|
||||
* @param namePattern a regex pattern to match field names, can be {@literal null}.
|
||||
* @param typeName the name of the type to exclude, can be {@literal null}.
|
||||
*/
|
||||
public FieldMatch(String namePattern, String typeName) {
|
||||
|
||||
Assert.isTrue(!(namePattern == null && typeName == null), "Either name patter or type name must be given!");
|
||||
|
||||
this.namePattern = namePattern;
|
||||
this.typeName = typeName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the given {@link Field} matches the defined {@link FieldMatch}.
|
||||
*
|
||||
* @param field must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public boolean matches(Field field) {
|
||||
|
||||
if (namePattern != null && !field.getName().matches(namePattern)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (typeName != null && !field.getType().getName().equals(typeName)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,235 @@
|
||||
/*
|
||||
* Copyright 2011-2012 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.mapping.context;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.core.convert.converter.Converter;
|
||||
import org.springframework.data.mapping.PersistentProperty;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Abstraction of a path of {@link PersistentProperty}s.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
class DefaultPersistentPropertyPath<T extends PersistentProperty<T>> implements PersistentPropertyPath<T> {
|
||||
|
||||
private enum PropertyNameConverter implements Converter<PersistentProperty<?>, String> {
|
||||
|
||||
INSTANCE;
|
||||
|
||||
public String convert(PersistentProperty<?> source) {
|
||||
return source.getName();
|
||||
}
|
||||
}
|
||||
|
||||
private final List<T> properties;
|
||||
|
||||
/**
|
||||
* Creates a new {@link DefaultPersistentPropertyPath} for the given {@link PersistentProperty}s.
|
||||
*
|
||||
* @param properties must not be {@literal null}.
|
||||
*/
|
||||
public DefaultPersistentPropertyPath(List<T> properties) {
|
||||
|
||||
Assert.notNull(properties);
|
||||
Assert.isTrue(!properties.isEmpty());
|
||||
|
||||
this.properties = properties;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.context.PersistentPropertyPath#toDotPath()
|
||||
*/
|
||||
public String toDotPath() {
|
||||
return toPath(null, null);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.context.PersistentPropertyPath#toDotPath(org.springframework.core.convert.converter.Converter)
|
||||
*/
|
||||
public String toDotPath(Converter<? super T, String> converter) {
|
||||
return toPath(null, converter);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.context.PersistentPropertyPath#toPath(java.lang.String)
|
||||
*/
|
||||
public String toPath(String delimiter) {
|
||||
return toPath(delimiter, null);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.context.PersistentPropertyPath#toPath(java.lang.String, org.springframework.core.convert.converter.Converter)
|
||||
*/
|
||||
public String toPath(String delimiter, Converter<? super T, String> converter) {
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
Converter<? super T, String> converterToUse = (Converter<? super T, String>) (converter == null ? PropertyNameConverter.INSTANCE
|
||||
: converter);
|
||||
String delimiterToUse = delimiter == null ? "." : delimiter;
|
||||
|
||||
List<String> result = new ArrayList<String>();
|
||||
|
||||
for (T property : properties) {
|
||||
result.add(converterToUse.convert(property));
|
||||
}
|
||||
|
||||
return StringUtils.collectionToDelimitedString(result, delimiterToUse);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.context.PersistentPropertyPath#getLeafProperty()
|
||||
*/
|
||||
public T getLeafProperty() {
|
||||
return properties.get(properties.size() - 1);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.context.PersistentPropertyPath#getBaseProperty()
|
||||
*/
|
||||
public T getBaseProperty() {
|
||||
return properties.get(0);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.context.PersistentPropertyPath#isBasePathOf(org.springframework.data.mapping.context.PersistentPropertyPath)
|
||||
*/
|
||||
public boolean isBasePathOf(PersistentPropertyPath<T> path) {
|
||||
|
||||
if (path == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Iterator<T> iterator = path.iterator();
|
||||
|
||||
for (T property : this) {
|
||||
|
||||
if (!iterator.hasNext()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
T reference = iterator.next();
|
||||
|
||||
if (!property.equals(reference)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.context.PersistentPropertyPath#getExtensionForBaseOf(org.springframework.data.mapping.context.PersistentPropertyPath)
|
||||
*/
|
||||
public PersistentPropertyPath<T> getExtensionForBaseOf(PersistentPropertyPath<T> base) {
|
||||
|
||||
if (!base.isBasePathOf(this)) {
|
||||
return this;
|
||||
}
|
||||
|
||||
List<T> properties = new ArrayList<T>();
|
||||
Iterator<T> iterator = iterator();
|
||||
|
||||
for (int i = 0; i < base.getLength(); i++) {
|
||||
iterator.next();
|
||||
}
|
||||
|
||||
while (iterator.hasNext()) {
|
||||
properties.add(iterator.next());
|
||||
}
|
||||
|
||||
return new DefaultPersistentPropertyPath<T>(properties);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.context.PersistentPropertyPath#getParentPath()
|
||||
*/
|
||||
public PersistentPropertyPath<T> getParentPath() {
|
||||
int size = properties.size();
|
||||
if (size <= 1) {
|
||||
return this;
|
||||
}
|
||||
return new DefaultPersistentPropertyPath<T>(properties.subList(0, size - 1));
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.context.PersistentPropertyPath#getLength()
|
||||
*/
|
||||
public int getLength() {
|
||||
return properties.size();
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see java.lang.Iterable#iterator()
|
||||
*/
|
||||
public Iterator<T> iterator() {
|
||||
return properties.iterator();
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see java.lang.Object#equals(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (obj == null || !getClass().equals(obj.getClass())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
DefaultPersistentPropertyPath<?> that = (DefaultPersistentPropertyPath<?>) obj;
|
||||
|
||||
return this.properties.equals(that.properties);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see java.lang.Object#hashCode()
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return properties.hashCode();
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see java.lang.Object#toString()
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return toDotPath();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
* Copyright 2011-2012 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.mapping.context;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import org.springframework.data.mapping.PersistentEntity;
|
||||
import org.springframework.data.mapping.PersistentProperty;
|
||||
import org.springframework.data.mapping.PropertyPath;
|
||||
import org.springframework.data.util.TypeInformation;
|
||||
|
||||
/**
|
||||
* This interface defines the overall context including all known PersistentEntity instances and methods to obtain
|
||||
* instances on demand. it is used internally to establish associations between entities and also at runtime to obtain
|
||||
* entities by name.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
* @author Jon Brisbin
|
||||
* @author Graeme Rocher
|
||||
*/
|
||||
public interface MappingContext<E extends PersistentEntity<?, P>, P extends PersistentProperty<P>> {
|
||||
|
||||
/**
|
||||
* Returns all {@link PersistentEntity}s held in the context.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
Collection<E> getPersistentEntities();
|
||||
|
||||
/**
|
||||
* Returns a {@link PersistentEntity} for the given {@link Class}. Will return {@literal null} for types that are
|
||||
* considered simple ones.
|
||||
*
|
||||
* @see org.springframework.data.mapping.model.SimpleTypeHolder#isSimpleType(Class)
|
||||
* @param type must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
E getPersistentEntity(Class<?> type);
|
||||
|
||||
/**
|
||||
* Returns a {@link PersistentEntity} for the given {@link TypeInformation}. Will return {@literal null} for types
|
||||
* that are considered simple ones.
|
||||
*
|
||||
* @see org.springframework.data.mapping.model.SimpleTypeHolder#isSimpleType(Class)
|
||||
* @param type must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
E getPersistentEntity(TypeInformation<?> type);
|
||||
|
||||
/**
|
||||
* Returns the {@link PersistentEntity} mapped by the given {@link PersistentProperty}.
|
||||
*
|
||||
* @param persistentProperty
|
||||
* @return the {@link PersistentEntity} mapped by the given {@link PersistentProperty} or null if no
|
||||
* {@link PersistentEntity} exists for it or the {@link PersistentProperty} does not refer to an entity (the
|
||||
* type of the property is considered simple see
|
||||
* {@link org.springframework.data.mapping.model.SimpleTypeHolder#isSimpleType(Class)}).
|
||||
*/
|
||||
E getPersistentEntity(P persistentProperty);
|
||||
|
||||
/**
|
||||
* Returns all {@link PersistentProperty}s for the given path expression based on the given {@link PropertyPath}.
|
||||
*
|
||||
* @param <T>
|
||||
* @param type
|
||||
* @param path
|
||||
* @return
|
||||
*/
|
||||
PersistentPropertyPath<P> getPersistentPropertyPath(PropertyPath propertyPath);
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* Copyright 2011-2012 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.mapping.context;
|
||||
|
||||
import org.springframework.context.ApplicationEvent;
|
||||
import org.springframework.data.mapping.PersistentEntity;
|
||||
import org.springframework.data.mapping.PersistentProperty;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Base implementation of an {@link ApplicationEvent} refering to a {@link PersistentEntity}.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
* @author Jon Brisbin
|
||||
* @param <E> the {@link PersistentEntity} the context was created for
|
||||
* @param <P> the {@link PersistentProperty} the {@link PersistentEntity} consists of
|
||||
*/
|
||||
public class MappingContextEvent<E extends PersistentEntity<?, P>, P extends PersistentProperty<P>> extends
|
||||
ApplicationEvent {
|
||||
|
||||
private static final long serialVersionUID = 1336466833846092490L;
|
||||
|
||||
private final MappingContext<?, ?> source;
|
||||
private final E entity;
|
||||
|
||||
/**
|
||||
* Creates a new {@link MappingContextEvent} for the given {@link MappingContext} and {@link PersistentEntity}.
|
||||
*
|
||||
* @param source must not be {@literal null}.
|
||||
* @param entity must not be {@literal null}.
|
||||
*/
|
||||
public MappingContextEvent(MappingContext<?, ?> source, E entity) {
|
||||
|
||||
super(source);
|
||||
|
||||
Assert.notNull(source);
|
||||
Assert.notNull(entity);
|
||||
|
||||
this.source = source;
|
||||
this.entity = entity;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link PersistentEntity} the event was created for.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public E getPersistentEntity() {
|
||||
return entity;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the {@link MappingContextEvent} was triggered by the given {@link MappingContext}.
|
||||
*
|
||||
* @param context the {@link MappingContext} that potentially created the event.
|
||||
* @return
|
||||
*/
|
||||
public boolean wasEmittedBy(MappingContext<?, ?> context) {
|
||||
return this.source.equals(context);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,114 @@
|
||||
/*
|
||||
* Copyright 2011 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.mapping.context;
|
||||
|
||||
import org.springframework.core.convert.converter.Converter;
|
||||
import org.springframework.data.mapping.PersistentProperty;
|
||||
|
||||
/**
|
||||
* Abstraction of a path of {@link PersistentProperty}s.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public interface PersistentPropertyPath<T extends PersistentProperty<T>> extends Iterable<T> {
|
||||
|
||||
/**
|
||||
* Returns the dot based path notation using {@link PersistentProperty#getName()}.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
String toDotPath();
|
||||
|
||||
/**
|
||||
* Returns the dot based path notation using the given {@link Converter} to translate individual
|
||||
* {@link PersistentProperty}s to path segments.
|
||||
*
|
||||
* @param converter
|
||||
* @return
|
||||
*/
|
||||
String toDotPath(Converter<? super T, String> converter);
|
||||
|
||||
/**
|
||||
* Returns a {@link String} path with the given delimiter based on the {@link PersistentProperty#getName()}.
|
||||
*
|
||||
* @param delimiter will default to {@code .} if {@literal null} is given.
|
||||
* @return
|
||||
*/
|
||||
String toPath(String delimiter);
|
||||
|
||||
/**
|
||||
* Returns a {@link String} path with the given delimiter using the given {@link Converter} for
|
||||
* {@link PersistentProperty} to String conversion.
|
||||
*
|
||||
* @param delimiter will default to {@code .} if {@literal null} is given.
|
||||
* @param converter will default to use {@link PersistentProperty#getName()}.
|
||||
* @return
|
||||
*/
|
||||
String toPath(String delimiter, Converter<? super T, String> converter);
|
||||
|
||||
/**
|
||||
* Returns the last property in the {@link PersistentPropertyPath}. So for {@code foo.bar} it will return the
|
||||
* {@link PersistentProperty} for {@code bar}. For a simple {@code foo} it returns {@link PersistentProperty} for
|
||||
* {@code foo}.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
T getLeafProperty();
|
||||
|
||||
/**
|
||||
* Returns the first property in the {@link PersistentPropertyPath}. So for {@code foo.bar} it will return the
|
||||
* {@link PersistentProperty} for {@code foo}. For a simple {@code foo} it returns {@link PersistentProperty} for
|
||||
* {@code foo}.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
T getBaseProperty();
|
||||
|
||||
/**
|
||||
* Returns whether the given {@link PersistentPropertyPath} is a base path of the current one. This means that the
|
||||
* current {@link PersistentPropertyPath} is basically an extension of the given one.
|
||||
*
|
||||
* @param path
|
||||
* @return
|
||||
*/
|
||||
boolean isBasePathOf(PersistentPropertyPath<T> path);
|
||||
|
||||
/**
|
||||
* Returns the sub-path of the current one as if it was based on the given base path. So for a current path
|
||||
* {@code foo.bar} and a given base {@code foo} it would return {@code bar}. If the given path is not a base of the
|
||||
* the current one the current {@link PersistentPropertyPath} will be returned as is.
|
||||
*
|
||||
* @param base
|
||||
* @return
|
||||
*/
|
||||
PersistentPropertyPath<T> getExtensionForBaseOf(PersistentPropertyPath<T> base);
|
||||
|
||||
/**
|
||||
* Returns the parent path of the current {@link PersistentPropertyPath}, i.e. the path without the leaf property.
|
||||
* This happens up to the base property. So for a direct property reference calling this method will result in
|
||||
* returning the property.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
PersistentPropertyPath<T> getParentPath();
|
||||
|
||||
/**
|
||||
* Returns the length of the {@link PersistentPropertyPath}.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
int getLength();
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
/**
|
||||
* Mapping context API and implementation base classes.
|
||||
*/
|
||||
package org.springframework.data.mapping.context;
|
||||
@@ -0,0 +1,312 @@
|
||||
/*
|
||||
* Copyright 2011-2012 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.mapping.model;
|
||||
|
||||
import java.beans.PropertyDescriptor;
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.data.annotation.Reference;
|
||||
import org.springframework.data.mapping.Association;
|
||||
import org.springframework.data.mapping.PersistentEntity;
|
||||
import org.springframework.data.mapping.PersistentProperty;
|
||||
import org.springframework.data.util.TypeInformation;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Simple impementation of {@link PersistentProperty}.
|
||||
*
|
||||
* @author Jon Brisbin
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public abstract class AbstractPersistentProperty<P extends PersistentProperty<P>> implements PersistentProperty<P> {
|
||||
|
||||
protected final String name;
|
||||
protected final PropertyDescriptor propertyDescriptor;
|
||||
protected final TypeInformation<?> information;
|
||||
protected final Class<?> rawType;
|
||||
protected final Field field;
|
||||
protected final Association<P> association;
|
||||
protected final PersistentEntity<?, P> owner;
|
||||
private final SimpleTypeHolder simpleTypeHolder;
|
||||
|
||||
public AbstractPersistentProperty(Field field, PropertyDescriptor propertyDescriptor, PersistentEntity<?, P> owner,
|
||||
SimpleTypeHolder simpleTypeHolder) {
|
||||
|
||||
Assert.notNull(field);
|
||||
Assert.notNull(simpleTypeHolder);
|
||||
Assert.notNull(owner);
|
||||
|
||||
this.name = field.getName();
|
||||
this.rawType = field.getType();
|
||||
this.information = owner.getTypeInformation().getProperty(this.name);
|
||||
this.propertyDescriptor = propertyDescriptor;
|
||||
this.field = field;
|
||||
this.association = isAssociation() ? createAssociation() : null;
|
||||
this.owner = owner;
|
||||
this.simpleTypeHolder = simpleTypeHolder;
|
||||
}
|
||||
|
||||
protected abstract Association<P> createAssociation();
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.PersistentProperty#getOwner()
|
||||
*/
|
||||
public PersistentEntity<?, P> getOwner() {
|
||||
return owner;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.PersistentProperty#getName()
|
||||
*/
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.PersistentProperty#getType()
|
||||
*/
|
||||
public Class<?> getType() {
|
||||
return information.getType();
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.PersistentProperty#getRawType()
|
||||
*/
|
||||
public Class<?> getRawType() {
|
||||
return this.rawType;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.PersistentProperty#getTypeInformation()
|
||||
*/
|
||||
public TypeInformation<?> getTypeInformation() {
|
||||
return information;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.PersistentProperty#getPersistentEntityType()
|
||||
*/
|
||||
public Iterable<? extends TypeInformation<?>> getPersistentEntityType() {
|
||||
|
||||
List<TypeInformation<?>> result = new ArrayList<TypeInformation<?>>();
|
||||
|
||||
TypeInformation<?> type = getTypeInformation();
|
||||
|
||||
if (isEntity()) {
|
||||
result.add(type);
|
||||
}
|
||||
|
||||
if (type.isCollectionLike() || isMap()) {
|
||||
TypeInformation<?> nestedType = getTypeInformationIfNotSimpleType(getTypeInformation().getActualType());
|
||||
if (nestedType != null) {
|
||||
result.add(nestedType);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private TypeInformation<?> getTypeInformationIfNotSimpleType(TypeInformation<?> information) {
|
||||
return information == null || simpleTypeHolder.isSimpleType(information.getType()) ? null : information;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.PersistentProperty#getGetter()
|
||||
*/
|
||||
public Method getGetter() {
|
||||
|
||||
if (propertyDescriptor == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
Method getter = propertyDescriptor.getReadMethod();
|
||||
|
||||
if (getter == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return rawType.isAssignableFrom(getter.getReturnType()) ? getter : null;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.PersistentProperty#getSetter()
|
||||
*/
|
||||
public Method getSetter() {
|
||||
|
||||
if (propertyDescriptor == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
Method setter = propertyDescriptor.getWriteMethod();
|
||||
|
||||
if (setter == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return setter.getParameterTypes()[0].isAssignableFrom(rawType) ? setter : null;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.PersistentProperty#getField()
|
||||
*/
|
||||
public Field getField() {
|
||||
return field;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.PersistentProperty#getSpelExpression()
|
||||
*/
|
||||
public String getSpelExpression() {
|
||||
return null;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.PersistentProperty#isTransient()
|
||||
*/
|
||||
public boolean isTransient() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.PersistentProperty#shallBePersisted()
|
||||
*/
|
||||
public boolean shallBePersisted() {
|
||||
return !isTransient();
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.PersistentProperty#isAssociation()
|
||||
*/
|
||||
public boolean isAssociation() {
|
||||
if (field.isAnnotationPresent(Reference.class)) {
|
||||
return true;
|
||||
}
|
||||
for (Annotation annotation : field.getDeclaredAnnotations()) {
|
||||
if (annotation.annotationType().isAnnotationPresent(Reference.class)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public Association<P> getAssociation() {
|
||||
return association;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.PersistentProperty#isCollectionLike()
|
||||
*/
|
||||
public boolean isCollectionLike() {
|
||||
return information.isCollectionLike();
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.PersistentProperty#isMap()
|
||||
*/
|
||||
public boolean isMap() {
|
||||
return Map.class.isAssignableFrom(getType());
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.PersistentProperty#isArray()
|
||||
*/
|
||||
public boolean isArray() {
|
||||
return getType().isArray();
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.PersistentProperty#isEntity()
|
||||
*/
|
||||
public boolean isEntity() {
|
||||
|
||||
TypeInformation<?> actualType = information.getActualType();
|
||||
boolean isComplexType = actualType == null ? false : !simpleTypeHolder.isSimpleType(actualType.getType());
|
||||
return isComplexType && !isTransient() && !isCollectionLike() && !isMap();
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.PersistentProperty#getComponentType()
|
||||
*/
|
||||
public Class<?> getComponentType() {
|
||||
|
||||
if (!isMap() && !isCollectionLike()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
TypeInformation<?> componentType = information.getComponentType();
|
||||
return componentType == null ? null : componentType.getType();
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.PersistentProperty#getMapValueType()
|
||||
*/
|
||||
public Class<?> getMapValueType() {
|
||||
return isMap() ? information.getMapValueType().getType() : null;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see java.lang.Object#equals(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!(obj instanceof AbstractPersistentProperty)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
AbstractPersistentProperty<?> that = (AbstractPersistentProperty<?>) obj;
|
||||
return this.field.equals(that.field);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see java.lang.Object#hashCode()
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return this.field.hashCode();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,121 @@
|
||||
/*
|
||||
* Copyright (c) 2011 by the original author(s).
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.mapping.model;
|
||||
|
||||
import java.beans.PropertyDescriptor;
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.Field;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.core.annotation.AnnotationUtils;
|
||||
import org.springframework.data.annotation.Id;
|
||||
import org.springframework.data.annotation.Reference;
|
||||
import org.springframework.data.annotation.Transient;
|
||||
import org.springframework.data.annotation.Version;
|
||||
import org.springframework.data.mapping.Association;
|
||||
import org.springframework.data.mapping.PersistentEntity;
|
||||
import org.springframework.data.mapping.PersistentProperty;
|
||||
|
||||
/**
|
||||
* Special {@link PersistentProperty} that takes annotations at a property into account.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public abstract class AnnotationBasedPersistentProperty<P extends PersistentProperty<P>> extends
|
||||
AbstractPersistentProperty<P> {
|
||||
|
||||
private final Value value;
|
||||
|
||||
/**
|
||||
* Creates a new {@link AnnotationBasedPersistentProperty}.
|
||||
*
|
||||
* @param field
|
||||
* @param propertyDescriptor
|
||||
* @param owner
|
||||
*/
|
||||
public AnnotationBasedPersistentProperty(Field field, PropertyDescriptor propertyDescriptor,
|
||||
PersistentEntity<?, P> owner, SimpleTypeHolder simpleTypeHolder) {
|
||||
|
||||
super(field, propertyDescriptor, owner, simpleTypeHolder);
|
||||
this.value = field.getAnnotation(Value.class);
|
||||
field.isAnnotationPresent(Autowired.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Inspects a potentially available {@link Value} annotation at the property and returns the {@link String} value of
|
||||
* it.
|
||||
*
|
||||
* @see org.springframework.data.mapping.model.AbstractPersistentProperty#getSpelExpression()
|
||||
*/
|
||||
@Override
|
||||
public String getSpelExpression() {
|
||||
return value == null ? null : value.value();
|
||||
}
|
||||
|
||||
/**
|
||||
* Considers plain transient fields, fields annotated with {@link Transient}, {@link Value} or {@link Autowired} as
|
||||
* transien.
|
||||
*
|
||||
* @see org.springframework.data.mapping.BasicPersistentProperty#isTransient()
|
||||
*/
|
||||
@Override
|
||||
public boolean isTransient() {
|
||||
|
||||
boolean isTransient = super.isTransient() || field.isAnnotationPresent(Transient.class);
|
||||
|
||||
return isTransient || field.isAnnotationPresent(Value.class) || field.isAnnotationPresent(Autowired.class);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.PersistentProperty#isIdProperty()
|
||||
*/
|
||||
public boolean isIdProperty() {
|
||||
return AnnotationUtils.getAnnotation(field, Id.class) != null;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.PersistentProperty#isVersionProperty()
|
||||
*/
|
||||
public boolean isVersionProperty() {
|
||||
return AnnotationUtils.getAnnotation(field, Version.class) != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Considers the property an {@link Association} if it is annotated with {@link Reference}.
|
||||
*/
|
||||
@Override
|
||||
public boolean isAssociation() {
|
||||
|
||||
if (isTransient()) {
|
||||
return false;
|
||||
}
|
||||
if (field.isAnnotationPresent(Reference.class)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// TODO: do we need this? Shouldn't the section above already find that annotation?
|
||||
for (Annotation annotation : field.getDeclaredAnnotations()) {
|
||||
if (annotation.annotationType().isAnnotationPresent(Reference.class)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,283 @@
|
||||
/*
|
||||
* Copyright 2011-2012 by the original author(s).
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.mapping.model;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.TreeSet;
|
||||
|
||||
import org.springframework.data.annotation.TypeAlias;
|
||||
import org.springframework.data.mapping.Association;
|
||||
import org.springframework.data.mapping.AssociationHandler;
|
||||
import org.springframework.data.mapping.PersistentEntity;
|
||||
import org.springframework.data.mapping.PersistentProperty;
|
||||
import org.springframework.data.mapping.PreferredConstructor;
|
||||
import org.springframework.data.mapping.PropertyHandler;
|
||||
import org.springframework.data.util.TypeInformation;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Simple value object to capture information of {@link PersistentEntity}s.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
* @author Jon Brisbin
|
||||
* @author Patryk Wasik
|
||||
*/
|
||||
public class BasicPersistentEntity<T, P extends PersistentProperty<P>> implements MutablePersistentEntity<T, P> {
|
||||
|
||||
private final PreferredConstructor<T, P> constructor;
|
||||
private final TypeInformation<T> information;
|
||||
private final Set<P> properties;
|
||||
private final Set<Association<P>> associations;
|
||||
|
||||
private P idProperty;
|
||||
private P versionProperty;
|
||||
|
||||
/**
|
||||
* Creates a new {@link BasicPersistentEntity} from the given {@link TypeInformation}.
|
||||
*
|
||||
* @param information must not be {@literal null}.
|
||||
*/
|
||||
public BasicPersistentEntity(TypeInformation<T> information) {
|
||||
this(information, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link BasicPersistentEntity} for the given {@link TypeInformation} and {@link Comparator}. The given
|
||||
* {@link Comparator} will be used to define the order of the {@link PersistentProperty} instances added to the
|
||||
* entity.
|
||||
*
|
||||
* @param information must not be {@literal null}
|
||||
* @param comparator
|
||||
*/
|
||||
public BasicPersistentEntity(TypeInformation<T> information, Comparator<P> comparator) {
|
||||
|
||||
Assert.notNull(information);
|
||||
|
||||
this.information = information;
|
||||
this.properties = comparator == null ? new HashSet<P>() : new TreeSet<P>(comparator);
|
||||
this.constructor = new PreferredConstructorDiscoverer<T, P>(information, this).getConstructor();
|
||||
this.associations = comparator == null ? new HashSet<Association<P>>() : new TreeSet<Association<P>>(
|
||||
new AssociationComparator<P>(comparator));
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.PersistentEntity#getPersistenceConstructor()
|
||||
*/
|
||||
public PreferredConstructor<T, P> getPersistenceConstructor() {
|
||||
return constructor;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.PersistentEntity#isConstructorArgument(org.springframework.data.mapping.PersistentProperty)
|
||||
*/
|
||||
public boolean isConstructorArgument(PersistentProperty<?> property) {
|
||||
return constructor == null ? false : constructor.isConstructorParameter(property);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.PersistentEntity#isIdProperty(org.springframework.data.mapping.PersistentProperty)
|
||||
*/
|
||||
public boolean isIdProperty(PersistentProperty<?> property) {
|
||||
return this.idProperty == null ? false : this.idProperty.equals(property);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.PersistentEntity#isVersionProperty(org.springframework.data.mapping.PersistentProperty)
|
||||
*/
|
||||
public boolean isVersionProperty(PersistentProperty<?> property) {
|
||||
return this.versionProperty == null ? false : this.versionProperty.equals(property);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.PersistentEntity#getName()
|
||||
*/
|
||||
public String getName() {
|
||||
return getType().getName();
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.PersistentEntity#getIdProperty()
|
||||
*/
|
||||
public P getIdProperty() {
|
||||
return idProperty;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.PersistentEntity#getVersionProperty()
|
||||
*/
|
||||
public P getVersionProperty() {
|
||||
return versionProperty;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.PersistentEntity#hasIdProperty()
|
||||
*/
|
||||
public boolean hasIdProperty() {
|
||||
return idProperty != null;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.PersistentEntity#hasVersionProperty()
|
||||
*/
|
||||
public boolean hasVersionProperty() {
|
||||
return versionProperty != null;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.MutablePersistentEntity#addPersistentProperty(P)
|
||||
*/
|
||||
public void addPersistentProperty(P property) {
|
||||
|
||||
Assert.notNull(property);
|
||||
properties.add(property);
|
||||
|
||||
if (property.isIdProperty()) {
|
||||
|
||||
if (this.idProperty != null) {
|
||||
throw new MappingException(String.format(
|
||||
"Attempt to add id property %s but already have property %s registered "
|
||||
+ "as id. Check your mapping configuration!", property.getField(), idProperty.getField()));
|
||||
}
|
||||
|
||||
this.idProperty = property;
|
||||
}
|
||||
|
||||
if (property.isVersionProperty()) {
|
||||
|
||||
if (this.versionProperty != null) {
|
||||
throw new MappingException(String.format(
|
||||
"Attempt to add version property %s but already have property %s registered "
|
||||
+ "as version. Check your mapping configuration!", property.getField(), versionProperty.getField()));
|
||||
}
|
||||
|
||||
this.versionProperty = property;
|
||||
}
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.MutablePersistentEntity#addAssociation(org.springframework.data.mapping.model.Association)
|
||||
*/
|
||||
public void addAssociation(Association<P> association) {
|
||||
associations.add(association);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.PersistentEntity#getPersistentProperty(java.lang.String)
|
||||
*/
|
||||
public P getPersistentProperty(String name) {
|
||||
|
||||
for (P property : properties) {
|
||||
if (property.getName().equals(name)) {
|
||||
return property;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.PersistentEntity#getType()
|
||||
*/
|
||||
public Class<T> getType() {
|
||||
return information.getType();
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.PersistentEntity#getTypeAlias()
|
||||
*/
|
||||
public Object getTypeAlias() {
|
||||
|
||||
TypeAlias alias = getType().getAnnotation(TypeAlias.class);
|
||||
return alias == null ? null : StringUtils.hasText(alias.value()) ? alias.value() : null;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.PersistentEntity#getTypeInformation()
|
||||
*/
|
||||
public TypeInformation<T> getTypeInformation() {
|
||||
return information;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.PersistentEntity#doWithProperties(org.springframework.data.mapping.PropertyHandler)
|
||||
*/
|
||||
public void doWithProperties(PropertyHandler<P> handler) {
|
||||
Assert.notNull(handler);
|
||||
for (P property : properties) {
|
||||
if (!property.isTransient() && !property.isAssociation()) {
|
||||
handler.doWithPersistentProperty(property);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.PersistentEntity#doWithAssociations(org.springframework.data.mapping.AssociationHandler)
|
||||
*/
|
||||
public void doWithAssociations(AssociationHandler<P> handler) {
|
||||
Assert.notNull(handler);
|
||||
for (Association<P> association : associations) {
|
||||
handler.doWithAssociation(association);
|
||||
}
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.MutablePersistentEntity#verify()
|
||||
*/
|
||||
public void verify() {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Simple {@link Comparator} adaptor to delegate ordering to the inverse properties of the association.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
private static final class AssociationComparator<P extends PersistentProperty<P>> implements
|
||||
Comparator<Association<P>>, Serializable {
|
||||
|
||||
private static final long serialVersionUID = 4508054194886854513L;
|
||||
private final Comparator<P> delegate;
|
||||
|
||||
public AssociationComparator(Comparator<P> delegate) {
|
||||
Assert.notNull(delegate);
|
||||
this.delegate = delegate;
|
||||
}
|
||||
|
||||
public int compare(Association<P> left, Association<P> right) {
|
||||
return delegate.compare(left.getInverse(), right.getInverse());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,175 @@
|
||||
/*
|
||||
* Copyright 2011-2012 by the original author(s).
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.mapping.model;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import org.springframework.core.convert.ConversionService;
|
||||
import org.springframework.data.mapping.PersistentEntity;
|
||||
import org.springframework.data.mapping.PersistentProperty;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
|
||||
/**
|
||||
* Value object to allow creation of objects using the metamodel, setting and getting properties.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public class BeanWrapper<E extends PersistentEntity<T, ?>, T> {
|
||||
|
||||
private final T bean;
|
||||
private final ConversionService conversionService;
|
||||
|
||||
/**
|
||||
* Creates a new {@link BeanWrapper} for the given bean instance and {@link ConversionService}. If
|
||||
* {@link ConversionService} is {@literal null} no property type conversion will take place.
|
||||
*
|
||||
* @param <E>
|
||||
* @param <T>
|
||||
* @param bean must not be {@literal null}
|
||||
* @param conversionService
|
||||
* @return
|
||||
*/
|
||||
public static <E extends PersistentEntity<T, ?>, T> BeanWrapper<E, T> create(T bean,
|
||||
ConversionService conversionService) {
|
||||
return new BeanWrapper<E, T>(bean, conversionService);
|
||||
}
|
||||
|
||||
private BeanWrapper(T bean, ConversionService conversionService) {
|
||||
Assert.notNull(bean);
|
||||
this.bean = bean;
|
||||
this.conversionService = conversionService;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the given {@link PersistentProperty} to the given value. Will do type conversion if a
|
||||
* {@link ConversionService} is configured. Will use the accessor method of the given {@link PersistentProperty} if it
|
||||
* has one or field access otherwise.
|
||||
*
|
||||
* @param property must not be {@literal null}.
|
||||
* @param value
|
||||
*/
|
||||
public void setProperty(PersistentProperty<?> property, Object value) {
|
||||
setProperty(property, value, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the given {@link PersistentProperty} to the given value. Will do type conversion if a
|
||||
* {@link ConversionService} is configured.
|
||||
*
|
||||
* @param property must not be {@literal null}.
|
||||
* @param value
|
||||
* @param fieldAccessOnly whether to only try accessing the field ({@literal true}) or try using the getter first.
|
||||
* @throws IllegalAccessException
|
||||
* @throws InvocationTargetException
|
||||
*/
|
||||
public void setProperty(PersistentProperty<?> property, Object value, boolean fieldAccessOnly) {
|
||||
|
||||
Method setter = property.getSetter();
|
||||
|
||||
try {
|
||||
|
||||
if (fieldAccessOnly || null == setter) {
|
||||
Object valueToSet = getPotentiallyConvertedValue(value, property.getType());
|
||||
ReflectionUtils.makeAccessible(property.getField());
|
||||
ReflectionUtils.setField(property.getField(), bean, valueToSet);
|
||||
return;
|
||||
}
|
||||
|
||||
Class<?>[] paramTypes = setter.getParameterTypes();
|
||||
Object valueToSet = getPotentiallyConvertedValue(value, paramTypes[0]);
|
||||
ReflectionUtils.makeAccessible(setter);
|
||||
ReflectionUtils.invokeMethod(setter, bean, valueToSet);
|
||||
|
||||
} catch (IllegalStateException e) {
|
||||
throw new MappingException("Could not set object property!", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value of the given {@link PersistentProperty} of the underlying bean instance.
|
||||
*
|
||||
* @param <S>
|
||||
* @param property
|
||||
* @return
|
||||
*/
|
||||
public Object getProperty(PersistentProperty<?> property) {
|
||||
return getProperty(property, property.getType(), false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value of the given {@link PersistentProperty} potentially converted to the given type.
|
||||
*
|
||||
* @param <S>
|
||||
* @param property must not be {@literal null}.
|
||||
* @param type
|
||||
* @param fieldAccessOnly
|
||||
* @return
|
||||
*/
|
||||
public <S> S getProperty(PersistentProperty<?> property, Class<? extends S> type, boolean fieldAccessOnly) {
|
||||
|
||||
try {
|
||||
Object obj;
|
||||
Field field = property.getField();
|
||||
Method getter = property.getGetter();
|
||||
|
||||
if (fieldAccessOnly || null == getter) {
|
||||
ReflectionUtils.makeAccessible(field);
|
||||
obj = ReflectionUtils.getField(field, bean);
|
||||
} else {
|
||||
ReflectionUtils.makeAccessible(getter);
|
||||
obj = ReflectionUtils.invokeMethod(getter, bean);
|
||||
}
|
||||
|
||||
return getPotentiallyConvertedValue(obj, type);
|
||||
|
||||
} catch (IllegalStateException e) {
|
||||
throw new MappingException(String.format("Could not read property %s of %s!", property.toString(),
|
||||
bean.toString()), e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the given source value if it is not assignable to the given target type.
|
||||
*
|
||||
* @param source
|
||||
* @param targetType
|
||||
* @return
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
private <S> S getPotentiallyConvertedValue(Object source, Class<S> targetType) {
|
||||
|
||||
boolean conversionServiceAvailable = conversionService != null;
|
||||
boolean conversionNeeded = source == null || !targetType.isAssignableFrom(source.getClass());
|
||||
|
||||
if (conversionServiceAvailable && conversionNeeded) {
|
||||
return conversionService.convert(source, targetType);
|
||||
}
|
||||
|
||||
return (S) source;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the underlying bean instance.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public T getBean() {
|
||||
return bean;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Copyright (c) 2011 by the original author(s).
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.mapping.model;
|
||||
|
||||
import org.springframework.data.mapping.PreferredConstructor.Parameter;
|
||||
import org.springframework.expression.EvaluationContext;
|
||||
import org.springframework.expression.Expression;
|
||||
import org.springframework.expression.spel.standard.SpelExpressionParser;
|
||||
|
||||
/**
|
||||
* {@link ParameterValueProvider} implementation that evaluates the {@link Parameter}s key against
|
||||
* {@link SpelExpressionParser} and {@link EvaluationContext}.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public class DefaultSpELExpressionEvaluator implements SpELExpressionEvaluator {
|
||||
|
||||
private final Object source;
|
||||
private final SpELContext factory;
|
||||
|
||||
/**
|
||||
* @param parser
|
||||
* @param factory
|
||||
*/
|
||||
public DefaultSpELExpressionEvaluator(Object source, SpELContext factory) {
|
||||
this.source = source;
|
||||
this.factory = factory;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.model.SpELExpressionEvaluator#evaluate(java.lang.String)
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> T evaluate(String expression) {
|
||||
|
||||
Expression parseExpression = factory.getParser().parseExpression(expression);
|
||||
return (T) parseExpression.getValue(factory.getEvaluationContext(source));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
/* Copyright (C) 2010 SpringSource
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.mapping.model;
|
||||
|
||||
/**
|
||||
* Thrown when an error occurs reading the mapping between object and datastore
|
||||
*
|
||||
* @author Graeme Rocher
|
||||
* @since 1.0
|
||||
*/
|
||||
public class IllegalMappingException extends RuntimeException {
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public IllegalMappingException(String s, Throwable throwable) {
|
||||
super(s, throwable);
|
||||
}
|
||||
|
||||
public IllegalMappingException(String s) {
|
||||
super(s);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,169 @@
|
||||
/*
|
||||
* Copyright 2012 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.mapping.model;
|
||||
|
||||
import org.springframework.data.mapping.PersistentEntity;
|
||||
import org.springframework.data.mapping.PersistentProperty;
|
||||
import org.springframework.data.mapping.context.MappingContext;
|
||||
import org.springframework.data.support.IsNewStrategy;
|
||||
import org.springframework.data.support.IsNewStrategyFactory;
|
||||
import org.springframework.data.support.IsNewStrategyFactorySupport;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* An {@link IsNewStrategyFactory} using a {@link MappingContext} to determine the {@link IsNewStrategy} to be returned
|
||||
* for a particular type. It will look for a version and id property on the {@link PersistentEntity} and return a
|
||||
* strategy instance that will refelctively inspect the property for {@literal null} values or {@literal null} or a
|
||||
* value of 0 in case of a version property.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public class MappingContextIsNewStrategyFactory extends IsNewStrategyFactorySupport {
|
||||
|
||||
private final MappingContext<? extends PersistentEntity<?, ?>, ?> context;
|
||||
|
||||
/**
|
||||
* Creates a new {@link MappingContextIsNewStrategyFactory} using the given {@link MappingContext}.
|
||||
*
|
||||
* @param context must not be {@literal null}.
|
||||
*/
|
||||
public MappingContextIsNewStrategyFactory(MappingContext<? extends PersistentEntity<?, ?>, ?> context) {
|
||||
|
||||
Assert.notNull(context, "MappingContext must not be null!");
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.support.IsNewStrategyFactorySupport#getFallBackStrategy(java.lang.Class)
|
||||
*/
|
||||
@Override
|
||||
protected IsNewStrategy doGetIsNewStrategy(Class<?> type) {
|
||||
|
||||
PersistentEntity<?, ?> entity = context.getPersistentEntity(type);
|
||||
|
||||
if (entity == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (entity.hasVersionProperty()) {
|
||||
return new PropertyIsNullOrZeroNumberIsNewStrategy(entity.getVersionProperty());
|
||||
} else if (entity.hasIdProperty()) {
|
||||
return new PropertyIsNullIsNewStrategy(entity.getIdProperty());
|
||||
} else {
|
||||
throw new MappingException(String.format("Cannot determine IsNewStrategy for type %s!", type));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link IsNewStrategy} implementation that will inspect a given {@link PersistentProperty} and call
|
||||
* {@link #decideIsNew(Object)} with the value retrieved by reflection.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
static abstract class PersistentPropertyInspectingIsNewStrategy implements IsNewStrategy {
|
||||
|
||||
private final PersistentProperty<?> property;
|
||||
|
||||
/**
|
||||
* Creates a new {@link PersistentPropertyInspectingIsNewStrategy} using the given {@link PersistentProperty}.
|
||||
*
|
||||
* @param property must not be {@literal null}.
|
||||
*/
|
||||
public PersistentPropertyInspectingIsNewStrategy(PersistentProperty<?> property) {
|
||||
Assert.notNull(property, "PersistentProperty must not be null!");
|
||||
this.property = property;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.model.IsNewStrategy#isNew(java.lang.Object)
|
||||
*/
|
||||
public boolean isNew(Object entity) {
|
||||
|
||||
BeanWrapper<PersistentEntity<Object, ?>, Object> wrapper = BeanWrapper.create(entity, null);
|
||||
Object propertyValue = wrapper.getProperty(property);
|
||||
|
||||
return decideIsNew(propertyValue);
|
||||
}
|
||||
|
||||
protected abstract boolean decideIsNew(Object property);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link IsNewStrategy} that does a check against {@literal null} for the given value and considers the object new if
|
||||
* the value given is {@literal null}.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
static class PropertyIsNullIsNewStrategy extends PersistentPropertyInspectingIsNewStrategy {
|
||||
|
||||
/**
|
||||
* Creates a new {@link PropertyIsNullIsNewStrategy} using the given {@link PersistentProperty}.
|
||||
*
|
||||
* @param property must not be {@literal null}.
|
||||
*/
|
||||
public PropertyIsNullIsNewStrategy(PersistentProperty<?> property) {
|
||||
super(property);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.model.MappingContextIsNewStrategyFactory.PersistentPropertyInspectingIsNewStrategy#decideIsNew(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
protected boolean decideIsNew(Object property) {
|
||||
return property == null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link IsNewStrategy} that considers property values of {@literal null} or 0 (in case of a {@link Number})
|
||||
* implementation as indicators for the new state.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
static class PropertyIsNullOrZeroNumberIsNewStrategy extends PersistentPropertyInspectingIsNewStrategy {
|
||||
|
||||
/**
|
||||
* Creates a new {@link PropertyIsNullOrZeroNumberIsNewStrategy} instance using the given {@link PersistentProperty}
|
||||
* .
|
||||
*
|
||||
* @param property must not be {@literal null}.
|
||||
*/
|
||||
public PropertyIsNullOrZeroNumberIsNewStrategy(PersistentProperty<?> property) {
|
||||
super(property);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.model.MappingContextIsNewStrategyFactory.PersistentPropertyInspectingIsNewStrategy#decideIsNew(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
protected boolean decideIsNew(Object property) {
|
||||
|
||||
if (property == null) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!(property instanceof Number)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return ((Number) property).longValue() == 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright (c) 2011 by the original author(s).
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.data.mapping.model;
|
||||
|
||||
/**
|
||||
* @author Jon Brisbin <jbrisbin@vmware.com>
|
||||
*/
|
||||
public class MappingException extends RuntimeException {
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public MappingException(String s) {
|
||||
super(s);
|
||||
}
|
||||
|
||||
public MappingException(String s, Throwable throwable) {
|
||||
super(s, throwable);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Copyright (c) 2011 by the original author(s).
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.data.mapping.model;
|
||||
|
||||
/**
|
||||
* @author Jon Brisbin <jbrisbin@vmware.com>
|
||||
*/
|
||||
public class MappingInstantiationException extends RuntimeException {
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public MappingInstantiationException(String s, Throwable throwable) {
|
||||
super(s, throwable);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright (c) 2011 by the original author(s).
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.mapping.model;
|
||||
|
||||
import org.springframework.data.mapping.Association;
|
||||
import org.springframework.data.mapping.PersistentEntity;
|
||||
import org.springframework.data.mapping.PersistentProperty;
|
||||
|
||||
/**
|
||||
* Interface capturing mutator methods for {@link PersistentEntity}s.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public interface MutablePersistentEntity<T, P extends PersistentProperty<P>> extends PersistentEntity<T, P> {
|
||||
|
||||
/**
|
||||
* Adds a {@link PersistentProperty} to the entity.
|
||||
*
|
||||
* @param property
|
||||
*/
|
||||
void addPersistentProperty(P property);
|
||||
|
||||
/**
|
||||
* Adds an {@link Association} to the entity.
|
||||
*
|
||||
* @param association
|
||||
*/
|
||||
void addAssociation(Association<P> association);
|
||||
|
||||
/**
|
||||
* Callback method to trigger validation of the {@link PersistentEntity}. As {@link MutablePersistentEntity} is not
|
||||
* immutable there might be some verification steps necessary after the object has reached is final state.
|
||||
*
|
||||
* @throws MappingException in case the entity is invalid
|
||||
*/
|
||||
void verify() throws MappingException;
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright (c) 2011-2012 by the original author(s).
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.mapping.model;
|
||||
|
||||
import org.springframework.data.mapping.PersistentProperty;
|
||||
import org.springframework.data.mapping.PreferredConstructor.Parameter;
|
||||
|
||||
/**
|
||||
* Callback interface to lookup values for a given {@link Parameter}.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public interface ParameterValueProvider<P extends PersistentProperty<P>> {
|
||||
|
||||
/**
|
||||
* Returns the value to be used for the given {@link Parameter} (usually when entity instances are created).
|
||||
*
|
||||
* @param parameter must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
<T> T getParameterValue(Parameter<T, P> parameter);
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
* Copyright 2012 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.mapping.model;
|
||||
|
||||
import org.springframework.data.mapping.PersistentEntity;
|
||||
import org.springframework.data.mapping.PersistentProperty;
|
||||
import org.springframework.data.mapping.PreferredConstructor;
|
||||
import org.springframework.data.mapping.PreferredConstructor.Parameter;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* {@link ParameterValueProvider} based on a {@link PersistentEntity} to use a {@link PropertyValueProvider} to lookup
|
||||
* the value of the property referenced by the given {@link Parameter}. Additionally a
|
||||
* {@link DefaultSpELExpressionEvaluator} can be configured to get property value resolution trumped by a SpEL
|
||||
* expression evaluation.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public class PersistentEntityParameterValueProvider<P extends PersistentProperty<P>> implements
|
||||
ParameterValueProvider<P> {
|
||||
|
||||
private final PersistentEntity<?, P> entity;
|
||||
private final PropertyValueProvider<P> provider;
|
||||
private final Object parent;
|
||||
|
||||
/**
|
||||
* Creates a new {@link PersistentEntityParameterValueProvider} for the given {@link PersistentEntity} and
|
||||
* {@link PropertyValueProvider}.
|
||||
*
|
||||
* @param entity must not be {@literal null}.
|
||||
* @param provider must not be {@literal null}.
|
||||
* @param parent the parent object being created currently, can be {@literal null}.
|
||||
*/
|
||||
public PersistentEntityParameterValueProvider(PersistentEntity<?, P> entity, PropertyValueProvider<P> provider,
|
||||
Object parent) {
|
||||
|
||||
Assert.notNull(entity);
|
||||
Assert.notNull(provider);
|
||||
|
||||
this.entity = entity;
|
||||
this.provider = provider;
|
||||
this.parent = parent;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.model.ParameterValueProvider#getParameterValue(org.springframework.data.mapping.PreferredConstructor.Parameter)
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> T getParameterValue(Parameter<T, P> parameter) {
|
||||
|
||||
PreferredConstructor<?, P> constructor = entity.getPersistenceConstructor();
|
||||
|
||||
if (constructor.isEnclosingClassParameter(parameter)) {
|
||||
return (T) parent;
|
||||
}
|
||||
|
||||
P property = entity.getPersistentProperty(parameter.getName());
|
||||
|
||||
if (property == null) {
|
||||
throw new MappingException(String.format("No property %s found on entity %s to bind constructor parameter to!",
|
||||
parameter.getName(), entity.getType()));
|
||||
}
|
||||
|
||||
return provider.getPropertyValue(property);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,133 @@
|
||||
/*
|
||||
* Copyright 2011-2012 by the original author(s).
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.mapping.model;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.core.LocalVariableTableParameterNameDiscoverer;
|
||||
import org.springframework.core.ParameterNameDiscoverer;
|
||||
import org.springframework.data.mapping.PersistentEntity;
|
||||
import org.springframework.data.mapping.PersistentProperty;
|
||||
import org.springframework.data.mapping.PreferredConstructor;
|
||||
import org.springframework.data.mapping.PreferredConstructor.Parameter;
|
||||
import org.springframework.data.util.ClassTypeInformation;
|
||||
import org.springframework.data.util.TypeInformation;
|
||||
|
||||
/**
|
||||
* Helper class to find a {@link PreferredConstructor}.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public class PreferredConstructorDiscoverer<T, P extends PersistentProperty<P>> {
|
||||
|
||||
private final ParameterNameDiscoverer nameDiscoverer = new LocalVariableTableParameterNameDiscoverer();
|
||||
|
||||
private PreferredConstructor<T, P> constructor;
|
||||
|
||||
/**
|
||||
* Creates a new {@link PreferredConstructorDiscoverer} for the given type.
|
||||
*
|
||||
* @param type must not be {@literal null}.
|
||||
*/
|
||||
public PreferredConstructorDiscoverer(Class<T> type) {
|
||||
this(ClassTypeInformation.from(type), null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link PreferredConstructorDiscoverer} for the given {@link PersistentEntity}.
|
||||
*
|
||||
* @param entity must not be {@literal null}.
|
||||
*/
|
||||
public PreferredConstructorDiscoverer(PersistentEntity<T, P> entity) {
|
||||
this(entity.getTypeInformation(), entity);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link PreferredConstructorDiscoverer} for the given type.
|
||||
*
|
||||
* @param type must not be {@literal null}.
|
||||
* @param entity
|
||||
*/
|
||||
protected PreferredConstructorDiscoverer(TypeInformation<T> type, PersistentEntity<T, P> entity) {
|
||||
|
||||
boolean noArgConstructorFound = false;
|
||||
int numberOfArgConstructors = 0;
|
||||
Class<?> rawOwningType = type.getType();
|
||||
|
||||
for (Constructor<?> constructor : rawOwningType.getDeclaredConstructors()) {
|
||||
|
||||
PreferredConstructor<T, P> preferredConstructor = buildPreferredConstructor(constructor, type, entity);
|
||||
|
||||
// Explicitly defined constructor trumps all
|
||||
if (preferredConstructor.isExplicitlyAnnotated()) {
|
||||
this.constructor = preferredConstructor;
|
||||
return;
|
||||
}
|
||||
|
||||
// No-arg constructor trumps custom ones
|
||||
if (this.constructor == null || preferredConstructor.isNoArgConstructor()) {
|
||||
this.constructor = preferredConstructor;
|
||||
}
|
||||
|
||||
if (preferredConstructor.isNoArgConstructor()) {
|
||||
noArgConstructorFound = true;
|
||||
} else {
|
||||
numberOfArgConstructors++;
|
||||
}
|
||||
}
|
||||
|
||||
if (!noArgConstructorFound && numberOfArgConstructors > 1) {
|
||||
this.constructor = null;
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||
private PreferredConstructor<T, P> buildPreferredConstructor(Constructor<?> constructor,
|
||||
TypeInformation<T> typeInformation, PersistentEntity<T, P> entity) {
|
||||
|
||||
List<TypeInformation<?>> parameterTypes = typeInformation.getParameterTypes(constructor);
|
||||
|
||||
if (parameterTypes.isEmpty()) {
|
||||
return new PreferredConstructor<T, P>((Constructor<T>) constructor);
|
||||
}
|
||||
|
||||
String[] parameterNames = nameDiscoverer.getParameterNames(constructor);
|
||||
Parameter<Object, P>[] parameters = new Parameter[parameterTypes.size()];
|
||||
Annotation[][] parameterAnnotations = constructor.getParameterAnnotations();
|
||||
|
||||
for (int i = 0; i < parameterTypes.size(); i++) {
|
||||
|
||||
String name = parameterNames == null ? null : parameterNames[i];
|
||||
TypeInformation<?> type = parameterTypes.get(i);
|
||||
Annotation[] annotations = parameterAnnotations[i];
|
||||
|
||||
parameters[i] = new Parameter(name, type, annotations, entity);
|
||||
}
|
||||
|
||||
return new PreferredConstructor<T, P>((Constructor<T>) constructor, parameters);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the discovered {@link PreferredConstructor}.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public PreferredConstructor<T, P> getConstructor() {
|
||||
return constructor;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright 2012 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.mapping.model;
|
||||
|
||||
import org.springframework.data.mapping.PersistentProperty;
|
||||
|
||||
/**
|
||||
* SPI for components to provide values for as {@link PersistentProperty}.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public interface PropertyValueProvider<P extends PersistentProperty<P>> {
|
||||
|
||||
/**
|
||||
* Returns a value for the given {@link PersistentProperty}.
|
||||
*
|
||||
* @param property will never be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
<T> T getPropertyValue(P property);
|
||||
}
|
||||
@@ -0,0 +1,129 @@
|
||||
/*
|
||||
* Copyright (c) 2011 by the original author(s).
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.mapping.model;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.HashSet;
|
||||
import java.util.Locale;
|
||||
import java.util.Set;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Simple container to hold a set of types to be considered simple types.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public class SimpleTypeHolder {
|
||||
|
||||
private static final Set<Class<?>> DEFAULTS = new HashSet<Class<?>>();
|
||||
|
||||
static {
|
||||
DEFAULTS.add(boolean.class);
|
||||
DEFAULTS.add(boolean[].class);
|
||||
DEFAULTS.add(long.class);
|
||||
DEFAULTS.add(long[].class);
|
||||
DEFAULTS.add(short.class);
|
||||
DEFAULTS.add(short[].class);
|
||||
DEFAULTS.add(int.class);
|
||||
DEFAULTS.add(int[].class);
|
||||
DEFAULTS.add(byte.class);
|
||||
DEFAULTS.add(byte[].class);
|
||||
DEFAULTS.add(float.class);
|
||||
DEFAULTS.add(float[].class);
|
||||
DEFAULTS.add(double.class);
|
||||
DEFAULTS.add(double[].class);
|
||||
DEFAULTS.add(char.class);
|
||||
DEFAULTS.add(char[].class);
|
||||
DEFAULTS.add(Boolean.class);
|
||||
DEFAULTS.add(Long.class);
|
||||
DEFAULTS.add(Short.class);
|
||||
DEFAULTS.add(Integer.class);
|
||||
DEFAULTS.add(Byte.class);
|
||||
DEFAULTS.add(Float.class);
|
||||
DEFAULTS.add(Double.class);
|
||||
DEFAULTS.add(Character.class);
|
||||
DEFAULTS.add(String.class);
|
||||
DEFAULTS.add(Date.class);
|
||||
DEFAULTS.add(Locale.class);
|
||||
DEFAULTS.add(Class.class);
|
||||
DEFAULTS.add(Enum.class);
|
||||
}
|
||||
|
||||
private final Set<Class<?>> simpleTypes;
|
||||
|
||||
/**
|
||||
* Creates a new {@link SimpleTypeHolder} containing the default types.
|
||||
*
|
||||
* @see #SimpleTypeHolder(Set, boolean)
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public SimpleTypeHolder() {
|
||||
this(Collections.EMPTY_SET, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link SimpleTypeHolder} to carry the given custom simple types. Registration of default simple types
|
||||
* can be deactivated by passing {@literal false} for {@code registerDefaults}.
|
||||
*
|
||||
* @param customSimpleTypes
|
||||
* @param registerDefaults
|
||||
*/
|
||||
public SimpleTypeHolder(Set<? extends Class<?>> customSimpleTypes, boolean registerDefaults) {
|
||||
|
||||
Assert.notNull(customSimpleTypes);
|
||||
this.simpleTypes = new HashSet<Class<?>>(customSimpleTypes);
|
||||
|
||||
if (registerDefaults) {
|
||||
this.simpleTypes.addAll(DEFAULTS);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy constructor to create a new {@link SimpleTypeHolder} that carries the given additional custom simple types.
|
||||
*
|
||||
* @param customSimpleTypes must not be {@literal null}
|
||||
* @param source must not be {@literal null}
|
||||
*/
|
||||
public SimpleTypeHolder(Set<? extends Class<?>> customSimpleTypes, SimpleTypeHolder source) {
|
||||
|
||||
Assert.notNull(customSimpleTypes);
|
||||
Assert.notNull(source);
|
||||
|
||||
this.simpleTypes = new HashSet<Class<?>>(customSimpleTypes);
|
||||
this.simpleTypes.addAll(source.simpleTypes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the given type is considered a simple one.
|
||||
*
|
||||
* @param type
|
||||
* @return
|
||||
*/
|
||||
public boolean isSimpleType(Class<?> type) {
|
||||
Assert.notNull(type);
|
||||
if (Object.class.equals(type)) {
|
||||
return true;
|
||||
}
|
||||
for (Class<?> clazz : simpleTypes) {
|
||||
if (type == clazz || clazz.isAssignableFrom(type)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,112 @@
|
||||
/*
|
||||
* Copyright 2012 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.mapping.model;
|
||||
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.context.expression.BeanFactoryResolver;
|
||||
import org.springframework.expression.EvaluationContext;
|
||||
import org.springframework.expression.ExpressionParser;
|
||||
import org.springframework.expression.PropertyAccessor;
|
||||
import org.springframework.expression.spel.standard.SpelExpressionParser;
|
||||
import org.springframework.expression.spel.support.StandardEvaluationContext;
|
||||
|
||||
/**
|
||||
* Simple factory to create {@link SpelExpressionParser} and {@link EvaluationContext} instances.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public class SpELContext {
|
||||
|
||||
private final SpelExpressionParser parser;
|
||||
private final PropertyAccessor accessor;
|
||||
private final BeanFactory factory;
|
||||
|
||||
/**
|
||||
* Creates a new {@link SpELContext} with the given {@link PropertyAccessor}. Defaults the
|
||||
* {@link SpelExpressionParser}.
|
||||
*
|
||||
* @param accessor
|
||||
*/
|
||||
public SpELContext(PropertyAccessor accessor) {
|
||||
this(accessor, null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link SpELContext} using the given {@link SpelExpressionParser} and {@link PropertyAccessor}. Will
|
||||
* default the {@link SpelExpressionParser} in case the given value for it is {@literal null}.
|
||||
*
|
||||
* @param parser
|
||||
* @param accessor
|
||||
*/
|
||||
public SpELContext(SpelExpressionParser parser, PropertyAccessor accessor) {
|
||||
this(accessor, parser, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy constructor to create a {@link SpELContext} using the given one's {@link PropertyAccessor} and
|
||||
* {@link SpelExpressionParser} as well as the given {@link BeanFactory}.
|
||||
*
|
||||
* @param source
|
||||
* @param factory
|
||||
*/
|
||||
public SpELContext(SpELContext source, BeanFactory factory) {
|
||||
this(source.accessor, source.parser, factory);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link SpELContext} using the given {@link SpelExpressionParser}, {@link PropertyAccessor} and
|
||||
* {@link BeanFactory}. Will default the {@link SpelExpressionParser} in case the given value for it is
|
||||
* {@literal null}.
|
||||
*
|
||||
* @param accessor
|
||||
* @param parser
|
||||
* @param factory
|
||||
*/
|
||||
private SpELContext(PropertyAccessor accessor, SpelExpressionParser parser, BeanFactory factory) {
|
||||
|
||||
this.parser = parser == null ? new SpelExpressionParser() : parser;
|
||||
this.accessor = accessor;
|
||||
this.factory = factory;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.model.SpELContext#getParser()
|
||||
*/
|
||||
public ExpressionParser getParser() {
|
||||
return this.parser;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.model.SpELContext#getEvaluationContext(java.lang.Object)
|
||||
*/
|
||||
public EvaluationContext getEvaluationContext(Object source) {
|
||||
|
||||
StandardEvaluationContext evaluationContext = new StandardEvaluationContext(source);
|
||||
|
||||
if (accessor != null) {
|
||||
evaluationContext.addPropertyAccessor(accessor);
|
||||
}
|
||||
|
||||
if (factory != null) {
|
||||
evaluationContext.setBeanResolver(new BeanFactoryResolver(factory));
|
||||
}
|
||||
|
||||
return evaluationContext;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright 2012 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.mapping.model;
|
||||
|
||||
/**
|
||||
* SPI for components that can evaluate Spring EL expressions.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public interface SpELExpressionEvaluator {
|
||||
|
||||
/**
|
||||
* Evaluates the given expression.
|
||||
*
|
||||
* @param expression
|
||||
* @return
|
||||
*/
|
||||
<T> T evaluate(String expression);
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
/*
|
||||
* Copyright 2012 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.mapping.model;
|
||||
|
||||
import org.springframework.core.convert.ConversionService;
|
||||
import org.springframework.data.mapping.PersistentProperty;
|
||||
import org.springframework.data.mapping.PreferredConstructor.Parameter;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* {@link ParameterValueProvider} that can be used to front a {@link ParameterValueProvider} delegate to prefer a Spel
|
||||
* expression evaluation over directly resolving the parameter value with the delegate.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public class SpELExpressionParameterValueProvider<P extends PersistentProperty<P>> implements ParameterValueProvider<P> {
|
||||
|
||||
private final SpELExpressionEvaluator evaluator;
|
||||
private final ParameterValueProvider<P> delegate;
|
||||
private final ConversionService conversionService;
|
||||
|
||||
/**
|
||||
* Creates a new {@link SpELExpressionParameterValueProvider} using the given {@link SpELExpressionEvaluator},
|
||||
* {@link ConversionService} and {@link ParameterValueProvider} delegate to forward calls to, that resolve parameters
|
||||
* that do not have a Spel expression configured with them.
|
||||
*
|
||||
* @param evaluator must not be {@literal null}.
|
||||
* @param conversionService must not be {@literal null}.
|
||||
* @param delegate must not be {@literal null}.
|
||||
*/
|
||||
public SpELExpressionParameterValueProvider(SpELExpressionEvaluator evaluator, ConversionService conversionService,
|
||||
ParameterValueProvider<P> delegate) {
|
||||
|
||||
Assert.notNull(evaluator, "SpELExpressionEvaluator must not be null!");
|
||||
Assert.notNull(conversionService, "ConversionService must not be null!");
|
||||
Assert.notNull(delegate, "ParameterValueProvider delegate must not be null!");
|
||||
|
||||
this.evaluator = evaluator;
|
||||
this.conversionService = conversionService;
|
||||
this.delegate = delegate;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.model.ParameterValueProvider#getParameterValue(org.springframework.data.mapping.PreferredConstructor.Parameter)
|
||||
*/
|
||||
public <T> T getParameterValue(Parameter<T, P> parameter) {
|
||||
|
||||
if (!parameter.hasSpelExpression()) {
|
||||
return delegate == null ? null : delegate.getParameterValue(parameter);
|
||||
}
|
||||
|
||||
Object object = evaluator.evaluate(parameter.getSpelExpression());
|
||||
return object == null ? null : potentiallyConvertSpelValue(object, parameter);
|
||||
}
|
||||
|
||||
/**
|
||||
* Hook to allow to massage the value resulting from the Spel expression evaluation. Default implementation will
|
||||
* leverage the configured {@link ConversionService} to massage the value into the parameter type.
|
||||
*
|
||||
* @param object the value to massage, will never be {@literal null}.
|
||||
* @param parameter the {@link Parameter} we create the value for
|
||||
* @return
|
||||
*/
|
||||
protected <T> T potentiallyConvertSpelValue(Object object, Parameter<T, P> parameter) {
|
||||
return conversionService.convert(object, parameter.getRawType());
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user