Skip to content

Commit b009d28

Browse files
committed
Added ODM Metadata Inheritance fixes spring-projects#340
1 parent 9516edd commit b009d28

File tree

3 files changed

+110
-35
lines changed

3 files changed

+110
-35
lines changed

core/src/main/java/org/springframework/ldap/odm/core/impl/ObjectMetaData.java

Lines changed: 44 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,11 @@
1818

1919
import org.slf4j.Logger;
2020
import org.slf4j.LoggerFactory;
21+
import org.springframework.core.annotation.AnnotatedElementUtils;
2122
import org.springframework.ldap.odm.annotations.Entry;
2223
import org.springframework.ldap.odm.annotations.Id;
2324
import org.springframework.ldap.support.LdapUtils;
25+
import org.springframework.util.ReflectionUtils;
2426
import org.springframework.util.StringUtils;
2527

2628
import javax.naming.Name;
@@ -85,29 +87,33 @@ public AttributeMetaData getAttribute(Field field) {
8587
return fieldToAttribute.get(field);
8688
}
8789

88-
public ObjectMetaData(Class<?> clazz) {
90+
public ObjectMetaData(final Class<?> clazz) {
8991
if (LOG.isDebugEnabled()) {
9092
LOG.debug(String.format("Extracting metadata from %1$s", clazz));
9193
}
9294

9395
// Get object class metadata - the @Entity annotation
94-
Entry entity = clazz.getAnnotation(Entry.class);
95-
if (entity != null) {
96+
// findAllMergedAnnotations will return set of inherited annotations and apply them from superclass down to subclass
97+
Set<Entry> entities = AnnotatedElementUtils.findAllMergedAnnotations(clazz,Entry.class);
98+
if (entities != null && !entities.isEmpty()) {
9699
// Default objectclass name to the class name unless it's specified
97100
// in @Entity(name={objectclass1, objectclass2});
98-
String[] localObjectClasses = entity.objectClasses();
99-
if (localObjectClasses != null && localObjectClasses.length > 0 && localObjectClasses[0].length() > 0) {
100-
for (String localObjectClass:localObjectClasses) {
101-
objectClasses.add(new CaseIgnoreString(localObjectClass));
101+
for (Entry entity: entities) {
102+
String[] localObjectClasses = entity.objectClasses();
103+
if (localObjectClasses.length > 0 && localObjectClasses[0].length() > 0) {
104+
for (String localObjectClass : localObjectClasses) {
105+
objectClasses.add(new CaseIgnoreString(localObjectClass));
106+
}
102107
}
103-
} else {
108+
String base = entity.base();
109+
if (StringUtils.hasText(base)) {
110+
this.base = LdapUtils.newLdapName(base);
111+
}
112+
}
113+
if(objectClasses.isEmpty()) {
104114
objectClasses.add(new CaseIgnoreString(clazz.getSimpleName()));
105115
}
106116

107-
String base = entity.base();
108-
if(StringUtils.hasText(base)) {
109-
this.base = LdapUtils.newLdapName(base);
110-
}
111117
} else {
112118
throw new MetaDataException(String.format("Class %1$s must have a class level %2$s annotation", clazz,
113119
Entry.class));
@@ -119,31 +125,34 @@ public ObjectMetaData(Class<?> clazz) {
119125
}
120126

121127
// Get field meta-data - the @Attribute annotation
122-
Field[] fields = clazz.getDeclaredFields();
123-
for (Field field : fields) {
124-
// So we can write to private fields
125-
field.setAccessible(true);
126-
127-
// Skip synthetic or static fields
128-
if (Modifier.isStatic(field.getModifiers()) || field.isSynthetic()) {
129-
continue;
130-
}
131-
132-
AttributeMetaData currentAttributeMetaData=new AttributeMetaData(field);
133-
if (currentAttributeMetaData.isId()) {
134-
if (idAttribute!=null) {
135-
// There can be only one id field
136-
throw new MetaDataException(
137-
String.format("You man have only one field with the %1$s annotation in class %2$s", Id.class, clazz));
128+
ReflectionUtils.doWithFields(clazz, new ReflectionUtils.FieldCallback() {
129+
@Override
130+
public void doWith(Field field) throws IllegalArgumentException {
131+
// So we can write to private fields
132+
field.setAccessible(true);
133+
134+
// Skip synthetic or static fields
135+
if (Modifier.isStatic(field.getModifiers()) || field.isSynthetic()) {
136+
return;
137+
}
138+
139+
AttributeMetaData currentAttributeMetaData=new AttributeMetaData(field);
140+
if (currentAttributeMetaData.isId()) {
141+
if (idAttribute!=null) {
142+
// There can be only one id field
143+
throw new MetaDataException(
144+
String.format("You man have only one field with the %1$s annotation in class %2$s", Id.class, clazz));
145+
}
146+
idAttribute=currentAttributeMetaData;
147+
}
148+
fieldToAttribute.put(field, currentAttributeMetaData);
149+
150+
if(currentAttributeMetaData.isDnAttribute()) {
151+
dnAttributes.add(currentAttributeMetaData);
152+
}
138153
}
139-
idAttribute=currentAttributeMetaData;
140-
}
141-
fieldToAttribute.put(field, currentAttributeMetaData);
142-
143-
if(currentAttributeMetaData.isDnAttribute()) {
144-
dnAttributes.add(currentAttributeMetaData);
145154
}
146-
}
155+
);
147156

148157
if (idAttribute == null) {
149158
throw new MetaDataException(

core/src/test/java/org/springframework/ldap/odm/core/impl/DefaultObjectDirectoryMapperTest.java

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,42 @@ public void testMapping() {
8080
assertField(entityData, "entryUUID", "entryUUID", null, false, false, false, true);
8181
}
8282

83+
@Test
84+
public void testMappingInherited() {
85+
assertThat(tested.manageClass(UnitTestWorker.class))
86+
.containsOnlyElementsOf(Arrays.asList("dn", "cn", "sn", "description", "telephoneNumber", "entryUUID", "objectclass", "workerId"));
87+
88+
DefaultObjectDirectoryMapper.EntityData entityData = tested.getMetaDataMap().get(UnitTestWorker.class);
89+
90+
assertThat(entityData).isNotNull();
91+
assertThat(entityData.ocFilter).isEqualTo(query().
92+
where("objectclass").is("inetOrgPerson")
93+
.and("objectclass").is("organizationalPerson")
94+
.and("objectclass").is("person")
95+
.and("objectclass").is("top")
96+
.and("objectclass").is("worker")
97+
.filter());
98+
99+
assertThat(entityData.metaData).hasSize(9);
100+
101+
AttributeMetaData idAttribute = entityData.metaData.getIdAttribute();
102+
assertThat(idAttribute.getField().getName()).isEqualTo("dn");
103+
assertThat(idAttribute.isId()).isTrue();
104+
assertThat(idAttribute.isBinary()).isFalse();
105+
assertThat(idAttribute.isDnAttribute()).isFalse();
106+
assertThat(idAttribute.isTransient()).isFalse();
107+
assertThat(idAttribute.isCollection()).isFalse();
108+
109+
assertField(entityData, "fullName", "cn", "cn", false, false, false, false);
110+
assertField(entityData, "lastName", "sn", null, false, false, false, false);
111+
assertField(entityData, "description", "description", null, false, false, true, false);
112+
assertField(entityData, "country", null, "c", false, true, false, false);
113+
assertField(entityData, "company", null, "ou", false, true, false, false);
114+
assertField(entityData, "telephoneNumber", "telephoneNumber", null, false, false, false, false);
115+
assertField(entityData, "entryUUID", "entryUUID", null, false, false, false, true);
116+
assertField(entityData, "workerId", "workerId", null, false, false, false, false);
117+
}
118+
83119
@Test
84120
public void testInvalidType() {
85121
try {
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
/*
2+
* Copyright 2005-2013 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.ldap.odm.core.impl;
18+
19+
import org.springframework.ldap.odm.annotations.Attribute;
20+
import org.springframework.ldap.odm.annotations.Entry;
21+
22+
/**
23+
* @author Robert Wilson
24+
*/
25+
@Entry(objectClasses = {"worker"})
26+
public class UnitTestWorker extends UnitTestPerson{
27+
@Attribute(name = "workerId")
28+
private String workerId;
29+
}
30+

0 commit comments

Comments
 (0)