Skip to content

Commit 27321e7

Browse files
authored
Merge pull request #1350 from grails/202
Use Variant of ServiceLoader to allow soft loading of META-INF/services classes
2 parents e0996be + c9c2566 commit 27321e7

File tree

5 files changed

+497
-9
lines changed

5 files changed

+497
-9
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
package org.grails.datastore.mapping.config
2+
3+
import groovy.transform.CompileStatic
4+
import groovy.transform.Internal
5+
import org.grails.datastore.mapping.core.Datastore
6+
import org.grails.datastore.mapping.services.Service
7+
import org.springframework.beans.factory.BeanFactory
8+
import org.springframework.beans.factory.config.AutowireCapableBeanFactory
9+
import org.springframework.beans.factory.config.ConfigurableBeanFactory
10+
import org.springframework.beans.factory.config.MethodInvokingFactoryBean
11+
import org.springframework.lang.Nullable
12+
13+
/**
14+
* Variant of {#link MethodInvokingFactoryBean} which returns the correct data service type instead of {@code java.lang.Object} so the Autowire with type works correctly.
15+
*/
16+
@Internal
17+
@CompileStatic
18+
class DatastoreServiceMethodInvokingFactoryBean extends MethodInvokingFactoryBean {
19+
20+
@Nullable
21+
private ConfigurableBeanFactory beanFactory
22+
23+
@Override
24+
Class<?> getObjectType() {
25+
arguments[0] as Class<?>
26+
}
27+
28+
@Override
29+
protected Object invokeWithTargetException() throws Exception {
30+
Object object = super.invokeWithTargetException()
31+
if (object) {
32+
((Service) object).setDatastore((Datastore) targetObject)
33+
if (beanFactory instanceof AutowireCapableBeanFactory) {
34+
((AutowireCapableBeanFactory) beanFactory).autowireBean(object)
35+
}
36+
}
37+
object
38+
}
39+
40+
@Override
41+
void setBeanFactory(BeanFactory beanFactory) {
42+
super.setBeanFactory(beanFactory)
43+
if (beanFactory instanceof ConfigurableBeanFactory) {
44+
this.beanFactory = (ConfigurableBeanFactory) beanFactory
45+
}
46+
}
47+
}
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
/*
2+
* Copyright 2017-2020 original 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+
* http://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.grails.datastore.mapping.services;
17+
18+
import groovy.transform.Internal;
19+
20+
import java.util.Optional;
21+
import java.util.ServiceConfigurationError;
22+
import java.util.function.Supplier;
23+
24+
/**
25+
* Default implementation of {@link ServiceDefinition}.
26+
*
27+
* @param <S> The type
28+
* @author Graeme Rocher
29+
* @since 1.0
30+
*/
31+
@Internal
32+
class DefaultServiceDefinition<S> implements ServiceDefinition<S> {
33+
private final String name;
34+
private final Optional<Class<S>> loadedClass;
35+
36+
/**
37+
* @param name The name
38+
* @param loadedClass The loaded class
39+
*/
40+
DefaultServiceDefinition(String name, Optional<Class<S>> loadedClass) {
41+
this.name = name;
42+
this.loadedClass = loadedClass;
43+
}
44+
45+
@Override
46+
public String getName() {
47+
return name;
48+
}
49+
50+
@Override
51+
public Class<S> getType() { return loadedClass.orElseThrow(() -> new ServiceConfigurationError("Call to load() when class '" + name + "' is not present")); }
52+
53+
@Override
54+
public boolean isPresent() {
55+
return loadedClass.isPresent();
56+
}
57+
58+
@Override
59+
public <X extends Throwable> S orElseThrow(Supplier<? extends X> exceptionSupplier) throws X {
60+
final Class<S> type = loadedClass.orElseThrow(exceptionSupplier);
61+
try {
62+
return type.newInstance();
63+
} catch (Throwable e) {
64+
throw exceptionSupplier.get();
65+
}
66+
}
67+
68+
@Override
69+
public S load() {
70+
return loadedClass.map(aClass -> {
71+
try {
72+
return aClass.newInstance();
73+
} catch (Throwable e) {
74+
throw new ServiceConfigurationError("Error loading service [" + aClass.getName() + "]: " + e.getMessage(), e);
75+
}
76+
}).orElseThrow(() -> new ServiceConfigurationError("Call to load() when class '" + name + "' is not present"));
77+
}
78+
}
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
/*
2+
* Copyright 2017-2020 original 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+
* http://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.grails.datastore.mapping.services;
17+
18+
import java.util.function.Supplier;
19+
20+
/**
21+
* A service that may or may not be present on the classpath.
22+
*
23+
* @param <T> The service type
24+
*/
25+
public interface ServiceDefinition<T> {
26+
27+
/**
28+
* @return The full class name of the service
29+
*/
30+
String getName();
31+
32+
/**
33+
* @return The type of the service
34+
*/
35+
Class<T> getType();
36+
37+
/**
38+
* @return is the service present
39+
*/
40+
boolean isPresent();
41+
42+
/**
43+
* Load the service of throw the given exception.
44+
*
45+
* @param exceptionSupplier The exception supplier
46+
* @param <X> The exception type
47+
* @return The instance
48+
* @throws X The exception concrete type
49+
*/
50+
<X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier) throws X;
51+
52+
/**
53+
* @return load the service
54+
*/
55+
T load();
56+
}

0 commit comments

Comments
 (0)