Skip to content

Commit c0beb13

Browse files
committed
Merge branch 'datacouch_1057_illegal_reflective_access' of github.com:spring-projects/spring-data-couchbase into datacouch_1057_illegal_reflective_access
2 parents 26c7d89 + ec4e237 commit c0beb13

File tree

6 files changed

+255
-40
lines changed

6 files changed

+255
-40
lines changed

pom.xml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -265,6 +265,17 @@
265265
</execution>
266266
</executions>
267267
</plugin>
268+
<plugin>
269+
<groupId>org.apache.maven.plugins</groupId>
270+
<artifactId>maven-jar-plugin</artifactId>
271+
<configuration>
272+
<archive>
273+
<manifestEntries>
274+
<Automatic-Module-Name>${java-module-name}</Automatic-Module-Name>
275+
</manifestEntries>
276+
</archive>
277+
</configuration>
278+
</plugin>
268279
<plugin>
269280
<groupId>org.apache.maven.plugins</groupId>
270281
<artifactId>maven-assembly-plugin</artifactId>

src/main/java/org/springframework/data/couchbase/core/convert/OtherConverters.java

Lines changed: 34 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -51,33 +51,43 @@ private OtherConverters() {}
5151
return converters;
5252
}
5353

54-
@WritingConverter public enum UuidToString implements Converter<UUID,String>
55-
{
56-
INSTANCE;
57-
58-
@Override
59-
public String convert(UUID source) {
60-
return source == null ? null : source.toString();
61-
}}
54+
@WritingConverter
55+
public enum UuidToString implements Converter<UUID, String> {
56+
INSTANCE;
57+
58+
@Override
59+
public String convert(UUID source) {
60+
return source == null ? null : source.toString();
61+
}
62+
}
6263

63-
@ReadingConverter public enum StringToUuid implements Converter<String,UUID>{INSTANCE;
64+
@ReadingConverter
65+
public enum StringToUuid implements Converter<String, UUID> {
66+
INSTANCE;
6467

65-
@Override
66-
public UUID convert(String source) {
67-
return source == null ? null : UUID.fromString(source);
68-
}}
68+
@Override
69+
public UUID convert(String source) {
70+
return source == null ? null : UUID.fromString(source);
71+
}
72+
}
6973

70-
@WritingConverter public enum BigIntegerToString implements Converter<BigInteger,String>{INSTANCE;
74+
@WritingConverter
75+
public enum BigIntegerToString implements Converter<BigInteger, String> {
76+
INSTANCE;
7177

72-
@Override
73-
public String convert(BigInteger source) {
74-
return source == null ? null : source.toString();
75-
}}
78+
@Override
79+
public String convert(BigInteger source) {
80+
return source == null ? null : source.toString();
81+
}
82+
}
7683

77-
@ReadingConverter public enum StringToBigInteger implements Converter<String,BigInteger>{INSTANCE;
84+
@ReadingConverter
85+
public enum StringToBigInteger implements Converter<String, BigInteger> {
86+
INSTANCE;
7887

79-
@Override
80-
public BigInteger convert(String source) {
81-
return source == null ? null : new BigInteger(source);
82-
}
83-
}}
88+
@Override
89+
public BigInteger convert(String source) {
90+
return source == null ? null : new BigInteger(source);
91+
}
92+
}
93+
}

src/main/java/org/springframework/data/couchbase/core/mapping/CouchbaseMappingContext.java

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2012-2021 the original author or authors
2+
* Copyright 2012-2020 the original author or authors
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -16,15 +16,13 @@
1616

1717
package org.springframework.data.couchbase.core.mapping;
1818

19-
import java.lang.reflect.InaccessibleObjectException;
2019
import java.util.Optional;
2120

2221
import org.springframework.beans.BeansException;
2322
import org.springframework.context.ApplicationContext;
2423
import org.springframework.context.ApplicationContextAware;
2524
import org.springframework.context.ApplicationEventPublisher;
2625
import org.springframework.data.couchbase.core.index.CouchbasePersistentEntityIndexCreator;
27-
import org.springframework.data.mapping.MappingException;
2826
import org.springframework.data.mapping.context.AbstractMappingContext;
2927
import org.springframework.data.mapping.context.MappingContextEvent;
3028
import org.springframework.data.mapping.model.FieldNamingStrategy;
@@ -138,12 +136,7 @@ public void setAutoIndexCreation(boolean autoCreateIndexes) {
138136
*/
139137
@Override
140138
protected Optional<BasicCouchbasePersistentEntity<?>> addPersistentEntity(TypeInformation<?> typeInformation) {
141-
Optional<BasicCouchbasePersistentEntity<?>> entity = null;
142-
try {
143-
entity = super.addPersistentEntity(typeInformation);
144-
} catch (InaccessibleObjectException ioe) {
145-
throw new MappingException("due to InaccessibleObjectException", ioe);
146-
}
139+
Optional<BasicCouchbasePersistentEntity<?>> entity = super.addPersistentEntity(typeInformation);
147140

148141
if (this.eventPublisher != null && entity.isPresent()) {
149142
if (this.indexCreator != null) {
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
/*
2+
* Copyright 2014-2021 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+
package org.springframework.data.couchbase.repository.cdi;
17+
18+
import java.lang.annotation.Annotation;
19+
import java.util.Optional;
20+
import java.util.Set;
21+
22+
import javax.enterprise.context.spi.CreationalContext;
23+
import javax.enterprise.inject.spi.Bean;
24+
import javax.enterprise.inject.spi.BeanManager;
25+
26+
import org.springframework.data.couchbase.core.CouchbaseOperations;
27+
import org.springframework.data.couchbase.repository.config.RepositoryOperationsMapping;
28+
import org.springframework.data.couchbase.repository.support.CouchbaseRepositoryFactory;
29+
import org.springframework.data.repository.cdi.CdiRepositoryBean;
30+
import org.springframework.data.repository.config.CustomRepositoryImplementationDetector;
31+
import org.springframework.util.Assert;
32+
33+
/**
34+
* A bean which represents a Couchbase repository.
35+
*
36+
* @author Mark Paluch
37+
*/
38+
public class CouchbaseRepositoryBean<T> extends CdiRepositoryBean<T> {
39+
40+
private final Bean<CouchbaseOperations> couchbaseOperationsBean;
41+
42+
/**
43+
* Creates a new {@link CouchbaseRepositoryBean}.
44+
*
45+
* @param operations must not be {@literal null}.
46+
* @param qualifiers must not be {@literal null}.
47+
* @param repositoryType must not be {@literal null}.
48+
* @param beanManager must not be {@literal null}.
49+
* @param detector detector for the custom {@link org.springframework.data.repository.Repository} implementations
50+
* {@link org.springframework.data.repository.config.CustomRepositoryImplementationDetector}, can be
51+
* {@literal null}.
52+
*/
53+
public CouchbaseRepositoryBean(Bean<CouchbaseOperations> operations, Set<Annotation> qualifiers,
54+
Class<T> repositoryType, BeanManager beanManager, CustomRepositoryImplementationDetector detector) {
55+
super(qualifiers, repositoryType, beanManager, Optional.of(detector));
56+
57+
Assert.notNull(operations, "Cannot create repository with 'null' for CouchbaseOperations.");
58+
this.couchbaseOperationsBean = operations;
59+
}
60+
61+
/*
62+
* (non-Javadoc)
63+
* @see org.springframework.data.repository.cdi.CdiRepositoryBean#create(javax.enterprise.context.spi.CreationalContext, java.lang.Class)
64+
*/
65+
@Override
66+
protected T create(CreationalContext<T> creationalContext, Class<T> repositoryType) {
67+
68+
CouchbaseOperations couchbaseOperations = getDependencyInstance(couchbaseOperationsBean, CouchbaseOperations.class);
69+
RepositoryOperationsMapping couchbaseOperationsMapping = new RepositoryOperationsMapping(couchbaseOperations);
70+
71+
return create(() -> new CouchbaseRepositoryFactory(couchbaseOperationsMapping), repositoryType);
72+
}
73+
74+
@Override
75+
public Class<? extends Annotation> getScope() {
76+
return couchbaseOperationsBean.getScope();
77+
}
78+
}
Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
/*
2+
* Copyright 2014-2021 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.data.couchbase.repository.cdi;
18+
19+
import java.lang.annotation.Annotation;
20+
import java.lang.reflect.Type;
21+
import java.util.HashMap;
22+
import java.util.Map;
23+
import java.util.Set;
24+
25+
import javax.enterprise.event.Observes;
26+
import javax.enterprise.inject.UnsatisfiedResolutionException;
27+
import javax.enterprise.inject.spi.AfterBeanDiscovery;
28+
import javax.enterprise.inject.spi.Bean;
29+
import javax.enterprise.inject.spi.BeanManager;
30+
import javax.enterprise.inject.spi.ProcessBean;
31+
32+
import org.springframework.data.couchbase.core.CouchbaseOperations;
33+
import org.springframework.data.repository.cdi.CdiRepositoryBean;
34+
import org.springframework.data.repository.cdi.CdiRepositoryExtensionSupport;
35+
36+
/**
37+
* A portable CDI extension which registers beans for Spring Data Couchbase repositories.
38+
*
39+
* @author Mark Paluch
40+
*/
41+
public class CouchbaseRepositoryExtension extends CdiRepositoryExtensionSupport {
42+
43+
private final Map<Set<Annotation>, Bean<CouchbaseOperations>> couchbaseOperationsMap = new HashMap<Set<Annotation>, Bean<CouchbaseOperations>>();
44+
45+
/**
46+
* Implementation of a an observer which checks for CouchbaseOperations beans and stores them in
47+
* {@link #couchbaseOperationsMap} for later association with corresponding repository beans.
48+
*
49+
* @param <T> The type.
50+
* @param processBean The annotated type as defined by CDI.
51+
*/
52+
@SuppressWarnings("unchecked")
53+
<T> void processBean(@Observes ProcessBean<T> processBean) {
54+
Bean<T> bean = processBean.getBean();
55+
for (Type type : bean.getTypes()) {
56+
if (type instanceof Class<?> && CouchbaseOperations.class.isAssignableFrom((Class<?>) type)) {
57+
couchbaseOperationsMap.put(bean.getQualifiers(), ((Bean<CouchbaseOperations>) bean));
58+
}
59+
}
60+
}
61+
62+
/**
63+
* Implementation of a an observer which registers beans to the CDI container for the detected Spring Data
64+
* repositories.
65+
* <p>
66+
* The repository beans are associated to the CouchbaseOperations using their qualifiers.
67+
*
68+
* @param beanManager The BeanManager instance.
69+
*/
70+
void afterBeanDiscovery(@Observes AfterBeanDiscovery afterBeanDiscovery, BeanManager beanManager) {
71+
for (Map.Entry<Class<?>, Set<Annotation>> entry : getRepositoryTypes()) {
72+
73+
Class<?> repositoryType = entry.getKey();
74+
Set<Annotation> qualifiers = entry.getValue();
75+
76+
CdiRepositoryBean<?> repositoryBean = createRepositoryBean(repositoryType, qualifiers, beanManager);
77+
afterBeanDiscovery.addBean(repositoryBean);
78+
registerBean(repositoryBean);
79+
}
80+
}
81+
82+
/**
83+
* Creates a {@link Bean}.
84+
*
85+
* @param <T> The type of the repository.
86+
* @param repositoryType The class representing the repository.
87+
* @param beanManager The BeanManager instance.
88+
* @return The bean.
89+
*/
90+
private <T> CdiRepositoryBean<T> createRepositoryBean(Class<T> repositoryType, Set<Annotation> qualifiers,
91+
BeanManager beanManager) {
92+
93+
Bean<CouchbaseOperations> couchbaseOperationsBean = this.couchbaseOperationsMap.get(qualifiers);
94+
95+
if (couchbaseOperationsBean == null) {
96+
throw new UnsatisfiedResolutionException(String.format("Unable to resolve a bean for '%s' with qualifiers %s.",
97+
CouchbaseOperations.class.getName(), qualifiers));
98+
}
99+
100+
return new CouchbaseRepositoryBean<T>(couchbaseOperationsBean, qualifiers, repositoryType, beanManager,
101+
getCustomImplementationDetector());
102+
}
103+
}

src/test/java/org/springframework/data/couchbase/core/mapping/MappingCouchbaseConverterTests.java

Lines changed: 27 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -68,17 +68,35 @@ void shouldNotThrowNPE() {
6868

6969
@Test
7070
void doesNotAllowSimpleType1() {
71-
assertThrows(MappingException.class, () -> converter.write("hello", new CouchbaseDocument()));
71+
try {
72+
converter.write("hello", new CouchbaseDocument());
73+
} catch(Exception e){
74+
if(!(e instanceof MappingException) && !e.getClass().getName().equals("java.lang.reflect.InaccessibleObjectException")){
75+
throw new RuntimeException("Should have thrown MappingException or InaccessibleObjectException", e);
76+
}
77+
}
7278
}
7379

7480
@Test
7581
void doesNotAllowSimpleType2() {
76-
assertThrows(MappingException.class, () -> converter.write(true, new CouchbaseDocument()));
82+
try {
83+
converter.write(true, new CouchbaseDocument());
84+
} catch(Exception e){
85+
if(!(e instanceof MappingException) && !e.getClass().getName().equals("java.lang.reflect.InaccessibleObjectException")){
86+
throw new RuntimeException("Should have thrown MappingException or InaccessibleObjectException", e);
87+
}
88+
}
7789
}
7890

7991
@Test
8092
void doesNotAllowSimpleType3() {
81-
assertThrows(MappingException.class, () -> converter.write(42, new CouchbaseDocument()));
93+
try {
94+
converter.write(42, new CouchbaseDocument());
95+
} catch(Exception e){
96+
if(!(e instanceof MappingException) && !e.getClass().getName().equals("java.lang.reflect.InaccessibleObjectException")){
97+
throw new RuntimeException("Should have thrown MappingException or InaccessibleObjectException", e);
98+
}
99+
}
82100
}
83101

84102
@Test
@@ -425,7 +443,8 @@ void writesAndReadsCustomConvertedClass() {
425443
CustomConversions customConversions = new CouchbaseCustomConversions(converters);
426444
converter.setCustomConversions(customConversions);
427445
converter.afterPropertiesSet();
428-
((CouchbaseMappingContext) converter.getMappingContext()).setSimpleTypeHolder(customConversions.getSimpleTypeHolder());
446+
((CouchbaseMappingContext) converter.getMappingContext())
447+
.setSimpleTypeHolder(customConversions.getSimpleTypeHolder());
429448

430449
CouchbaseDocument converted = new CouchbaseDocument();
431450

@@ -475,8 +494,8 @@ void writesAndReadsCustomFieldsConvertedClass() {
475494
CustomConversions customConversions = new CouchbaseCustomConversions(converters);
476495
converter.setCustomConversions(customConversions);
477496
converter.afterPropertiesSet();
478-
((CouchbaseMappingContext) converter.getMappingContext()).setSimpleTypeHolder(customConversions.getSimpleTypeHolder());
479-
497+
((CouchbaseMappingContext) converter.getMappingContext())
498+
.setSimpleTypeHolder(customConversions.getSimpleTypeHolder());
480499

481500
CouchbaseDocument converted = new CouchbaseDocument();
482501

@@ -526,7 +545,8 @@ void writesAndReadsClassContainingCustomConvertedObjects() {
526545
CustomConversions customConversions = new CouchbaseCustomConversions(converters);
527546
converter.setCustomConversions(customConversions);
528547
converter.afterPropertiesSet();
529-
((CouchbaseMappingContext) converter.getMappingContext()).setSimpleTypeHolder(customConversions.getSimpleTypeHolder());
548+
((CouchbaseMappingContext) converter.getMappingContext())
549+
.setSimpleTypeHolder(customConversions.getSimpleTypeHolder());
530550

531551
CouchbaseDocument converted = new CouchbaseDocument();
532552

0 commit comments

Comments
 (0)