Skip to content

Instantly share code, notes, and snippets.

@gissuebot
Created July 7, 2014 17:55
Show Gist options
  • Save gissuebot/d46c66a915cc5eefc076 to your computer and use it in GitHub Desktop.
Save gissuebot/d46c66a915cc5eefc076 to your computer and use it in GitHub Desktop.
Migrated attachment for Guice issue 62, comment 36
Index: src/com/google/inject/spi/CloseErrors.java
===================================================================
--- src/com/google/inject/spi/CloseErrors.java Mon Oct 06 13:42:22 BST 2008
+++ src/com/google/inject/spi/CloseErrors.java Mon Oct 06 13:42:22 BST 2008
@@ -0,0 +1,40 @@
+/**
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 com.google.inject.spi;
+
+/**
+ * A handler of exceptions when closing down resources.
+ * Implementations will typically create a collection of error messages so that all of the different
+ * close exceptions are collected together.
+ *
+ * @version $Revision: 1.1 $
+ */
+public interface CloseErrors {
+
+ /**
+ * Notification of a close exception
+ * @param key the key of the object being closed which is usually a {@link com.google.inject.Key}
+ * or {@link String}
+ * @param object the object being closed
+ * @param cause the exception thrown when the close was attempted
+ */
+ void closeError(Object key, Object object, Exception cause);
+
+ void throwIfNecessary() throws CloseFailedException;
+}
Index: test/com/google/inject/AllTests.java
===================================================================
--- test/com/google/inject/AllTests.java (revision 627)
+++ test/com/google/inject/AllTests.java Mon Oct 06 12:25:29 BST 2008
@@ -59,6 +59,7 @@
suite.addTestSuite(InjectionPointTest.class);
suite.addTestSuite(InjectorTest.class);
suite.addTestSuite(IntegrationTest.class);
+ suite.addTestSuite(CloseTest.class);
suite.addTestSuite(KeyTest.class);
suite.addTestSuite(LoggerInjectionTest.class);
suite.addTestSuite(ModuleTest.class);
Index: src/com/google/inject/AbstractModule.java
===================================================================
--- src/com/google/inject/AbstractModule.java (revision 627)
+++ src/com/google/inject/AbstractModule.java Fri Oct 03 16:37:08 BST 2008
@@ -26,6 +26,7 @@
import com.google.inject.spi.TypeConverter;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
+import org.aopalliance.intercept.ConstructorInterceptor;
import org.aopalliance.intercept.MethodInterceptor;
/**
@@ -167,6 +168,15 @@
}
/**
+ * @see Binder#bindConstructorInterceptor(com.google.inject.matcher.Matcher,
+ * org.aopalliance.intercept.ConstructorInterceptor[])
+ */
+ protected void bindConstructorInterceptor(Matcher<? super Class<?>> classMatcher,
+ ConstructorInterceptor... interceptors) {
+ binder.bindConstructorInterceptor(classMatcher, interceptors);
+ }
+
+ /**
* Adds a dependency from this module to {@code key}. When the injector is
* created, Guice will report an error if {@code key} cannot be injected.
* Note that this requirement may be satisfied by implicit binding, such as
Index: src/com/google/inject/spi/ConstructorInterceptorBinding.java
===================================================================
--- src/com/google/inject/spi/ConstructorInterceptorBinding.java Fri Oct 03 16:08:58 BST 2008
+++ src/com/google/inject/spi/ConstructorInterceptorBinding.java Fri Oct 03 16:08:58 BST 2008
@@ -0,0 +1,65 @@
+/**
+ * Copyright (C) 2008 Google Inc.
+ *
+ * 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 com.google.inject.spi;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import com.google.inject.matcher.Matcher;
+import java.util.Arrays;
+import static java.util.Collections.unmodifiableList;
+import java.util.List;
+import org.aopalliance.intercept.ConstructorInterceptor;
+
+/**
+ * Registration of {@link ConstructorInterceptor} instances for matching classes. Instances are created
+ * explicitly in a module using {@link com.google.inject.Binder#bindConstructorInterceptor(com.google.inject.matcher.Matcher, org.aopalliance.intercept.ConstructorInterceptor[])}
+ * statements:
+ * <pre>
+ * bindConstructorInterceptor(Matchers.subclassesOf(MyAction.class),
+ * new MyPostConstructionInterceptor());</pre>
+ *
+ * @author james.strachan@gmail.com (James Strachan)
+ */
+public final class ConstructorInterceptorBinding implements Element {
+ private final Object source;
+ private final Matcher<? super Class<?>> classMatcher;
+ private final List<ConstructorInterceptor> interceptors;
+
+ ConstructorInterceptorBinding(
+ Object source,
+ Matcher<? super Class<?>> classMatcher,
+ ConstructorInterceptor[] interceptors) {
+ this.source = checkNotNull(source, "source");
+ this.classMatcher = checkNotNull(classMatcher, "classMatcher");
+ this.interceptors = unmodifiableList(Arrays.asList(interceptors.clone()));
+ }
+
+ public Object getSource() {
+ return source;
+ }
+
+ public Matcher<? super Class<?>> getClassMatcher() {
+ return classMatcher;
+ }
+
+ public List<ConstructorInterceptor> getInterceptors() {
+ return interceptors;
+ }
+
+ public <T> T acceptVisitor(ElementVisitor<T> visitor) {
+ return visitor.visitConstructorInterceptorBinding(this);
+ }
+}
\ No newline at end of file
Index: src/com/google/inject/InjectorImpl.java
===================================================================
--- src/com/google/inject/InjectorImpl.java (revision 627)
+++ src/com/google/inject/InjectorImpl.java Mon Oct 06 14:01:20 BST 2008
@@ -23,19 +23,28 @@
import com.google.common.collect.Maps;
import com.google.common.collect.Multimap;
import com.google.common.collect.Multimaps;
+import com.google.common.collect.Sets;
import com.google.inject.internal.Annotations;
import com.google.inject.internal.BytecodeGen.Visibility;
import static com.google.inject.internal.BytecodeGen.newFastClass;
import com.google.inject.internal.Classes;
+import com.google.inject.internal.CloseErrorsImpl;
+import com.google.inject.internal.CloseableProvider;
+import com.google.inject.internal.CompositeCloser;
import com.google.inject.internal.ConfigurationException;
import com.google.inject.internal.Errors;
import com.google.inject.internal.ErrorsException;
import com.google.inject.internal.FailableCache;
import com.google.inject.internal.MatcherAndConverter;
import com.google.inject.internal.ToStringBuilder;
+import com.google.inject.matcher.Matcher;
import com.google.inject.spi.BindingTargetVisitor;
+import com.google.inject.spi.Closeable;
+import com.google.inject.spi.Closer;
import com.google.inject.spi.Dependency;
import com.google.inject.spi.InjectionPoint;
+import com.google.inject.spi.CloseErrors;
+import com.google.inject.spi.CloseFailedException;
import com.google.inject.util.Providers;
import java.lang.annotation.Annotation;
import java.lang.reflect.AnnotatedElement;
@@ -50,6 +59,8 @@
import java.util.Collections;
import java.util.List;
import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
import net.sf.cglib.reflect.FastClass;
import net.sf.cglib.reflect.FastMethod;
@@ -924,7 +935,7 @@
<T> Provider<T> getProviderOrThrow(final Key<T> key, Errors errors) throws ErrorsException {
final InternalFactory<? extends T> factory = getInternalFactory(key, errors);
- return new Provider<T>() {
+ return new CloseableProvider<T>() {
public T get() {
final Errors errors = new Errors();
try {
@@ -949,6 +960,13 @@
}
}
+ public void close(Closer closer, CloseErrors errors) {
+ if (factory instanceof Closeable) {
+ Closeable closeable = (Closeable) factory;
+ closeable.close(closer, errors);
+ }
+ }
+
@Override public String toString() {
return factory.toString();
}
@@ -1010,4 +1028,66 @@
.add("bindings", explicitBindings)
.toString();
}
+
+ /** Iterates through all bindings closing any {@link Closeable} providers which have pre destroy hooks */
+ public void close() throws CloseFailedException {
+ Set<Closer> closers = getInstancesOf(Closer.class);
+ if (closers.isEmpty()) {
+ return;
-}
+ }
+ Closer closer = new CompositeCloser(closers);
+ CloseErrorsImpl errors = new CloseErrorsImpl(this);
+
+ Set<Entry<Key<?>,Binding<?>>> entries = getBindings().entrySet();
+ for (Entry<Key<?>, Binding<?>> entry : entries) {
+ Binding<?> binding = entry.getValue();
+ Provider<?> provider = binding.getProvider();
+ if (provider instanceof Closeable) {
+ Closeable closeable = (Closeable) provider;
+ closeable.close(closer, errors);
+ }
+ }
+
+ errors.throwIfNecessary();
+ }
+
+ /**
+ * Returns a collection of all instances of the given base type
+ * @param baseClass the base type of objects required
+ * @param <T> the base type
+ * @return a set of objects returned from this injector
+ */
+ public <T> Set<T> getInstancesOf(Class<T> baseClass) {
+ Set<T> answer = Sets.newHashSet();
+ Set<Entry<Key<?>, Binding<?>>> entries = getBindings().entrySet();
+ for (Entry<Key<?>, Binding<?>> entry : entries) {
+ Key<?> key = entry.getKey();
+ if (baseClass.isAssignableFrom(key.getRawType())) {
+ Object value = getInstance(key);
+ if (value != null) {
+ T castValue = baseClass.cast(value);
+ answer.add(castValue);
+ }
+ }
+ }
+ return answer;
+ }
+
+ /**
+ * Returns a collection of all instances matching the given matcher
+ * @param matcher matches the types to return instances
+ * @return a set of objects returned from this injector
+ */
+ public <T> Set<T> getInstancesOf(Matcher<Class<T>> matcher) {
+ Set<T> answer = Sets.newHashSet();
+ Set<Entry<Key<?>, Binding<?>>> entries = getBindings().entrySet();
+ for (Entry<Key<?>, Binding<?>> entry : entries) {
+ Key<?> key = entry.getKey();
+ if (matcher.matches((Class<T>) key.getRawType())) {
+ Object value = getInstance(key);
+ answer.add((T) value);
+ }
+ }
+ return answer;
+ }
+}
Index: src/com/google/inject/internal/Errors.java
===================================================================
--- src/com/google/inject/internal/Errors.java (revision 627)
+++ src/com/google/inject/internal/Errors.java Mon Oct 06 12:03:18 BST 2008
@@ -322,7 +322,7 @@
return addMessage(null, messageFormat, arguments);
}
- private Errors addMessage(Throwable cause, String messageFormat, Object... arguments) {
+ public Errors addMessage(Throwable cause, String messageFormat, Object... arguments) {
String message = format(messageFormat, arguments);
addMessage(new Message(stripDuplicates(sources), message, cause));
return this;
Index: src/com/google/inject/internal/CompositeCloser.java
===================================================================
--- src/com/google/inject/internal/CompositeCloser.java Mon Oct 06 12:31:40 BST 2008
+++ src/com/google/inject/internal/CompositeCloser.java Mon Oct 06 12:31:40 BST 2008
@@ -0,0 +1,41 @@
+/**
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 com.google.inject.internal;
+
+import com.google.inject.spi.Closer;
+
+/**
+ * A Composite implementation of {@link Closer}
+ *
+ * @version $Revision: 1.1 $
+ * @author james.strachan@gmail.com (James Strachan)
+ */
+public class CompositeCloser implements Closer {
+ private final Iterable<Closer> closers;
+
+ public CompositeCloser(Iterable<Closer> closers) {
+ this.closers = closers;
+ }
+
+ public void close(Object object) throws Throwable {
+ for (Closer closer : closers) {
+ closer.close(object);
+ }
+ }
+}
Index: src/com/google/inject/ProviderToInternalFactoryAdapter.java
===================================================================
--- src/com/google/inject/ProviderToInternalFactoryAdapter.java (revision 627)
+++ src/com/google/inject/ProviderToInternalFactoryAdapter.java Mon Oct 06 12:50:42 BST 2008
@@ -18,12 +18,15 @@
import com.google.inject.internal.Errors;
import com.google.inject.internal.ErrorsException;
+import com.google.inject.spi.Closeable;
import com.google.inject.spi.Dependency;
+import com.google.inject.spi.Closer;
+import com.google.inject.spi.CloseErrors;
/**
* @author crazybob@google.com (Bob Lee)
*/
-class ProviderToInternalFactoryAdapter<T> implements Provider<T> {
+class ProviderToInternalFactoryAdapter<T> implements Provider<T>, Closeable {
private final InjectorImpl injector;
private final InternalFactory<? extends T> internalFactory;
@@ -50,6 +53,13 @@
}
}
+ public void close(Closer closer, CloseErrors errors) {
+ if (internalFactory instanceof Closeable) {
+ Closeable closeable = (Closeable) internalFactory;
+ closeable.close(closer, errors);
+ }
+ }
+
@Override public String toString() {
return internalFactory.toString();
}
Index: src/com/google/inject/spi/CloseFailedException.java
===================================================================
--- src/com/google/inject/spi/CloseFailedException.java Mon Oct 06 12:03:18 BST 2008
+++ src/com/google/inject/spi/CloseFailedException.java Mon Oct 06 12:03:18 BST 2008
@@ -0,0 +1,39 @@
+/**
+ * Copyright (C) 2008 Google Inc.
+ *
+ * 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 com.google.inject.spi;
+
+import com.google.inject.internal.Errors;
+import java.io.IOException;
+import java.util.List;
+
+/**
+ * Indicates that an attempt to close an injector or scope failed closing one or more bindings.
+ *
+ * @author james.strachan@gmail.com (James Strachan)
+ */
+public class CloseFailedException extends IOException {
+ private final List<Message> messages;
+
+ public CloseFailedException(List<Message> messages) {
+ super(Errors.format("Close errors", messages));
+ this.messages = messages;
+ }
+
+ public List<Message> getMessages() {
+ return messages;
+ }
+}
\ No newline at end of file
Index: jsr250/src/com/google/inject/jsr250/AnnotatedMethodCache.java
===================================================================
--- jsr250/src/com/google/inject/jsr250/AnnotatedMethodCache.java Mon Oct 06 14:03:00 BST 2008
+++ jsr250/src/com/google/inject/jsr250/AnnotatedMethodCache.java Mon Oct 06 14:03:00 BST 2008
@@ -0,0 +1,78 @@
+/**
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 com.google.inject.jsr250;
+
+import com.sun.tools.corba.se.idl.InvalidArgument;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Method;
+import java.util.Collections;
+import java.util.Map;
+import java.util.WeakHashMap;
+
+/**
+ * A cache which maintains which method is annotated by a given annotation for each class
+ *
+ * @version $Revision: 1.1 $
+ */
+class AnnotatedMethodCache {
+ private final Class<? extends Annotation> annotationType;
+ private Map<Class<?>, Method> methodCache = Collections
+ .synchronizedMap(new WeakHashMap<Class<?>, Method>());
+
+ public AnnotatedMethodCache(Class<? extends Annotation> annotationType) {
+ this.annotationType = annotationType;
+ }
+
+ /**
+ * Looks up the method which is annotated for the given type
+ */
+ public Method getMethod(Class<?> type) throws InvalidArgument {
+ // if we are invoked concurrently it doesn't matter if we look up the method
+ // concurrently - its the same instance that will be overwritten in the map
+ Method method = methodCache.get(type);
+ if (method == null) {
+ method = findMethodWithAnnotation(type, annotationType);
+ if (method != null) {
+ if (method.getParameterTypes().length != 0) {
+ throw new InvalidArgument("Method should have no arguments for @PostConstruct " + method);
+ }
+ methodCache.put(type, method);
+ }
+ }
+ return method;
+ }
+
+ protected Method findMethodWithAnnotation(Class<?> type,
+ Class<? extends Annotation> annotationType) {
+ Method[] methods = type.getDeclaredMethods();
+ for (Method method : methods) {
+ Annotation fromElement = method.getAnnotation(annotationType);
+ if (fromElement != null) {
+ return method;
+ }
+ }
+ if (!Object.class.equals(type)) {
+ Class superclass = type.getSuperclass();
+ if (superclass != null) {
+ return findMethodWithAnnotation(superclass, annotationType);
+ }
+ }
+ return null;
+ }
+}
Index: src/com/google/inject/InterceptorBindingProcessor.java
===================================================================
--- src/com/google/inject/InterceptorBindingProcessor.java (revision 627)
+++ src/com/google/inject/InterceptorBindingProcessor.java Fri Oct 03 16:24:04 BST 2008
@@ -18,6 +18,7 @@
import com.google.inject.internal.Errors;
import com.google.inject.spi.InterceptorBinding;
+import com.google.inject.spi.ConstructorInterceptorBinding;
/**
* Handles {@link Binder#bindInterceptor} commands.
@@ -40,6 +41,12 @@
return true;
}
+ @Override public Boolean visitConstructorInterceptorBinding(ConstructorInterceptorBinding command) {
+ proxyFactoryBuilder.constructorIntercept(
+ command.getClassMatcher(), command.getInterceptors());
+ return true;
+ }
+
ProxyFactory createProxyFactory() {
return proxyFactoryBuilder.create();
}
Index: src/com/google/inject/spi/Closers.java
===================================================================
--- src/com/google/inject/spi/Closers.java Mon Oct 06 13:42:22 BST 2008
+++ src/com/google/inject/spi/Closers.java Mon Oct 06 13:42:22 BST 2008
@@ -0,0 +1,50 @@
+/**
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 com.google.inject.spi;
+
+/**
+ * Some helper methods for working with the {@link Closer} interface
+ *
+ * @version $Revision: 1.1 $
+ */
+public final class Closers {
+
+ /**
+ * Closes the given object with the Closer if the object is not null
+ *
+ * @param key the Key or String name of the object to be closed
+ * @param objectToBeClosed the object that is going to be closed
+ * @param closer the strategy used to close the object
+ * @param errors the handler of exceptions if they occur
+ */
+ public static void close(Object key, Object objectToBeClosed, Closer closer, CloseErrors errors) {
+ if (objectToBeClosed != null) {
+ try {
+ closer.close(objectToBeClosed);
+ }
+ catch (Exception e) {
+ errors.closeError(key, objectToBeClosed, e);
+ }
+ catch (Throwable throwable) {
+ throwable
+ .printStackTrace(); //To change body of catch statement use File | Settings | File Templates.
+ }
+ }
+ }
+}
Index: servlet/src/com/google/inject/servlet/ServletScopes.java
===================================================================
--- servlet/src/com/google/inject/servlet/ServletScopes.java (revision 627)
+++ servlet/src/com/google/inject/servlet/ServletScopes.java Mon Oct 06 13:27:25 BST 2008
@@ -19,6 +19,11 @@
import com.google.inject.Key;
import com.google.inject.Provider;
import com.google.inject.Scope;
+import com.google.inject.internal.CloseableProvider;
+import com.google.inject.spi.CloseErrors;
+import com.google.inject.spi.Closer;
+import com.google.inject.spi.Closers;
+import java.util.Enumeration;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
@@ -37,7 +42,7 @@
public static final Scope REQUEST = new Scope() {
public <T> Provider<T> scope(Key<T> key, final Provider<T> creator) {
final String name = key.toString();
- return new Provider<T>() {
+ return new CloseableProvider<T>() {
public T get() {
HttpServletRequest request = GuiceFilter.getRequest();
synchronized (request) {
@@ -51,6 +56,18 @@
}
}
+ public void close(Closer closer, CloseErrors errors) {
+ HttpServletRequest request = GuiceFilter.getRequest();
+ synchronized (request) {
+ @SuppressWarnings("unchecked") Enumeration names = request.getAttributeNames();
+ while (names.hasMoreElements()) {
+ String name = (String) names.nextElement();
+ Object value = request.getAttribute(name);
+ Closers.close(name, value, closer, errors);
+ }
+ }
+ }
+
public String toString() {
return String.format("%s[%s]", creator, REQUEST);
}
@@ -68,7 +85,7 @@
public static final Scope SESSION = new Scope() {
public <T> Provider<T> scope(Key<T> key, final Provider<T> creator) {
final String name = key.toString();
- return new Provider<T>() {
+ return new CloseableProvider<T>() {
public T get() {
HttpSession session = GuiceFilter.getRequest().getSession();
synchronized (session) {
@@ -81,6 +98,19 @@
return t;
}
}
+
+ public void close(Closer closer, CloseErrors errors) {
+ HttpSession session = GuiceFilter.getRequest().getSession();
+ synchronized (session) {
+ @SuppressWarnings("unchecked") Enumeration names = session.getAttributeNames();
+ while (names.hasMoreElements()) {
+ String name = (String) names.nextElement();
+ Object value = session.getAttribute(name);
+ Closers.close(name, value, closer, errors);
+ }
+ }
+ }
+
public String toString() {
return String.format("%s[%s]", creator, SESSION);
}
Index: spring/src/com/google/inject/spring/DisposableBeanCloser.java
===================================================================
--- spring/src/com/google/inject/spring/DisposableBeanCloser.java Mon Oct 06 13:51:06 BST 2008
+++ spring/src/com/google/inject/spring/DisposableBeanCloser.java Mon Oct 06 13:51:06 BST 2008
@@ -0,0 +1,42 @@
+/**
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 com.google.inject.spring;
+
+import com.google.inject.spi.Closer;
+import org.springframework.beans.factory.DisposableBean;
+
+/**
+ * Invokes the {@link org.springframework.beans.factory.DisposableBean#destroy()} on any beans
+ * which are registered in a singleton scope when the injector is closed.
+ * <p>
+ * To install this lifecycle call the {@link SpringIntegration#bindLifecycle(com.google.inject.Binder)} method
+ * from your module.
+ *
+ * @see com.google.inject.Injector#close()
+ *
+ * @version $Revision: 1.1 $
+ */
+public class DisposableBeanCloser implements Closer {
+ public void close(Object object) throws Throwable {
+ if (object instanceof DisposableBean) {
+ DisposableBean disposableBean = (DisposableBean) object;
+ disposableBean.destroy();
+ }
+ }
+}
Index: src/com/google/inject/Scopes.java
===================================================================
--- src/com/google/inject/Scopes.java (revision 627)
+++ src/com/google/inject/Scopes.java Mon Oct 06 13:28:31 BST 2008
@@ -16,6 +16,11 @@
package com.google.inject;
+import com.google.inject.internal.CloseableProvider;
+import com.google.inject.spi.CloseErrors;
+import com.google.inject.spi.Closer;
+import com.google.inject.spi.Closers;
+
/**
* Built in scope implementations.
*
@@ -29,8 +34,8 @@
* One instance per {@link Injector}. Also see {@code @}{@link Singleton}.
*/
public static final Scope SINGLETON = new Scope() {
- public <T> Provider<T> scope(Key<T> key, final Provider<T> creator) {
- return new Provider<T>() {
+ public <T> Provider<T> scope(final Key<T> key, final Provider<T> creator) {
+ return new CloseableProvider<T>() {
private volatile T instance;
@@ -53,6 +58,13 @@
return instance;
}
+ public void close(Closer closer, CloseErrors errors) {
+ synchronized (Injector.class) {
+ Closers.close(key, instance, closer, errors);
+ instance = null;
+ }
+ }
+
public String toString() {
return String.format("%s[%s]", creator, SINGLETON);
}
Index: src/com/google/inject/internal/CloseErrorsImpl.java
===================================================================
--- src/com/google/inject/internal/CloseErrorsImpl.java Mon Oct 06 13:42:22 BST 2008
+++ src/com/google/inject/internal/CloseErrorsImpl.java Mon Oct 06 13:42:22 BST 2008
@@ -0,0 +1,47 @@
+/**
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 com.google.inject.internal;
+
+import com.google.inject.spi.CloseErrors;
+import com.google.inject.spi.CloseFailedException;
+
+/**
+ * The default implementation of @{link CloseErrors}
+ *
+ * @version $Revision: 1.1 $
+ */
+public class CloseErrorsImpl implements CloseErrors {
+ final Errors errors;
+
+ public CloseErrorsImpl(Object source) {
+ this.errors = new Errors(source);
+ }
+
+ public void closeError(Object key, Object object, Exception cause) {
+ errors.addMessage(cause, "Failed to close object %s with key %s", object, key);
+ }
+
+ public void throwIfNecessary() throws CloseFailedException {
+ if (!errors.hasErrors()) {
+ return;
+ }
+
+ throw new CloseFailedException(errors.getMessages());
+ }
+}
Index: src/com/google/inject/internal/CloseableProvider.java
===================================================================
--- src/com/google/inject/internal/CloseableProvider.java Mon Oct 06 13:42:22 BST 2008
+++ src/com/google/inject/internal/CloseableProvider.java Mon Oct 06 13:42:22 BST 2008
@@ -0,0 +1,31 @@
+/**
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 com.google.inject.internal;
+
+import com.google.inject.Provider;
+import com.google.inject.spi.Closeable;
+
+/**
+ * A simple interface which makes it a little easier to create anonymous classes which
+ * are both a {@link Provider} and implement {@link com.google.inject.spi.Closeable}
+ *
+ * @version $Revision: 1.1 $
+ */
+public interface CloseableProvider<T> extends Provider<T>, Closeable {
+}
Index: jsr250/test/com/google/inject/jsr250/PostConstructTest.java
===================================================================
--- jsr250/test/com/google/inject/jsr250/PostConstructTest.java Mon Oct 06 14:00:35 BST 2008
+++ jsr250/test/com/google/inject/jsr250/PostConstructTest.java Mon Oct 06 14:00:35 BST 2008
@@ -0,0 +1,82 @@
+/**
+ * Copyright (C) 2006 Google Inc.
+ *
+ * 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 com.google.inject.jsr250;
+
+import com.google.inject.AbstractModule;
+import com.google.inject.CreationException;
+import com.google.inject.Guice;
+import com.google.inject.Inject;
+import com.google.inject.Injector;
+import com.google.inject.Singleton;
+import com.google.inject.spi.CloseFailedException;
+import javax.annotation.PostConstruct;
+import javax.annotation.PreDestroy;
+import junit.framework.TestCase;
+
+/** @author james.strachan@gmail.com (James Strachan) */
+public class PostConstructTest extends TestCase {
+
+ public void testBeanInitialised() throws CreationException, CloseFailedException {
+ Injector injector = Guice.createInjector(new AbstractModule() {
+ protected void configure() {
+ Jsr250.bind(binder());
+
+ bind(MyBean.class).in(Singleton.class);
+ }
+ });
+
+ MyBean bean = injector.getInstance(MyBean.class);
+ assertNotNull("Should have instantiated the bean", bean);
+ assertTrue("The post construct lifecycle should have been invoked on bean", bean.postConstruct);
+
+ AnotherBean another = bean.another;
+ assertNotNull("Should have instantiated the another", another);
+ assertTrue("The post construct lifecycle should have been invoked on another", another.postConstruct);
+
+
+ assertFalse("The pre destroy lifecycle not should have been invoked on bean", bean.preDestroy);
+ injector.close();
+ assertTrue("The pre destroy lifecycle should have been invoked on bean", bean.preDestroy);
+ }
+
+ static class MyBean {
+ @Inject
+ public AnotherBean another;
+
+ public boolean postConstruct;
+ public boolean preDestroy;
+
+ @PostConstruct
+ public void postConstruct() throws Exception {
+ postConstruct = true;
+ }
+
+ @PreDestroy
+ public void preDestroy() throws Exception {
+ preDestroy = true;
+ }
+ }
+
+ static class AnotherBean {
+ public boolean postConstruct;
+
+ @PostConstruct
+ public void postConstruct() throws Exception {
+ postConstruct = true;
+ }
+ }
+}
\ No newline at end of file
Index: src/com/google/inject/ProxyFactoryBuilder.java
===================================================================
--- src/com/google/inject/ProxyFactoryBuilder.java (revision 627)
+++ src/com/google/inject/ProxyFactoryBuilder.java Fri Oct 03 16:24:04 BST 2008
@@ -22,6 +22,7 @@
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
+import org.aopalliance.intercept.ConstructorInterceptor;
import org.aopalliance.intercept.MethodInterceptor;
/**
@@ -32,6 +33,7 @@
class ProxyFactoryBuilder {
final List<MethodAspect> methodAspects = Lists.newArrayList();
+ final List<ConstructorAspect> constructorAspects = Lists.newArrayList();
/**
* Applies the given method interceptor to the methods matched by the class and method matchers.
@@ -55,8 +57,26 @@
return intercept(classMatcher, methodMatcher, Arrays.asList(interceptors));
}
+ /**
+ * Applies the given constructor interceptor to the methods matched by the class and method matchers.
+ *
+ * @param classMatcher matches classes the interceptor should apply to. For example: {@code
+ * only(Runnable.class)}.
+ * @param interceptors to apply
+ */
+ public ProxyFactoryBuilder constructorIntercept(Matcher<? super Class<?>> classMatcher,
+ List<ConstructorInterceptor> interceptors) {
+ constructorAspects.add(new ConstructorAspect(classMatcher, interceptors));
+ return this;
+ }
+
+ public ProxyFactoryBuilder constructorIntercept(Matcher<? super Class<?>> classMatcher,
+ ConstructorInterceptor... interceptors) {
+ return constructorIntercept(classMatcher, Arrays.asList(interceptors));
+ }
+
/** Creates a {@code ProxyFactory}. */
public ProxyFactory create() {
- return new ProxyFactory(new ArrayList<MethodAspect>(methodAspects));
+ return new ProxyFactory(new ArrayList<MethodAspect>(methodAspects), new ArrayList<ConstructorAspect>(constructorAspects));
}
}
Index: jsr250/src/com/google/inject/jsr250/PreDestroyCloser.java
===================================================================
--- jsr250/src/com/google/inject/jsr250/PreDestroyCloser.java Mon Oct 06 14:01:20 BST 2008
+++ jsr250/src/com/google/inject/jsr250/PreDestroyCloser.java Mon Oct 06 14:01:20 BST 2008
@@ -0,0 +1,51 @@
+/**
+ * Copyright (C) 2006 Google Inc.
+ *
+ * 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 com.google.inject.jsr250;
+
+import com.google.inject.spi.Closer;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import javax.annotation.PreDestroy;
+
+/**
+ * Supports the {@link javax.annotation.PreDestroy} annotation lifecycle from JSR250.
+ * <p>
+ * To install this interceptor call the {@link Jsr250#bind(com.google.inject.Binder)} method
+ * from your module.
+ *
+ * @author james.strachan@gmail.com (James Strachan)
+ * @version $Revision: 1.1 $
+ */
+public class PreDestroyCloser implements Closer {
+
+ private AnnotatedMethodCache methodCache = new AnnotatedMethodCache(PreDestroy.class);
+
+ public void close(Object object) throws Throwable {
+ Class<? extends Object> type = object.getClass();
+ Method method = methodCache.getMethod(type);
+ if (method != null) {
+ if (method != null) {
+ try {
+ method.invoke(object);
+ }
+ catch (InvocationTargetException e) {
+ throw e.getTargetException();
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
Index: src/com/google/inject/InternalFactoryToProviderAdapter.java
===================================================================
--- src/com/google/inject/InternalFactoryToProviderAdapter.java (revision 627)
+++ src/com/google/inject/InternalFactoryToProviderAdapter.java Mon Oct 06 12:50:42 BST 2008
@@ -20,12 +20,15 @@
import com.google.inject.internal.Errors;
import com.google.inject.internal.ErrorsException;
import com.google.inject.internal.SourceProvider;
+import com.google.inject.spi.Closeable;
import com.google.inject.spi.Dependency;
+import com.google.inject.spi.Closer;
+import com.google.inject.spi.CloseErrors;
/**
* @author crazybob@google.com (Bob Lee)
*/
-class InternalFactoryToProviderAdapter<T> implements InternalFactory<T> {
+class InternalFactoryToProviderAdapter<T> implements InternalFactory<T>, Closeable {
private final Provider<? extends T> provider;
private final Object source;
@@ -52,6 +55,13 @@
}
}
+ public void close(Closer closer, CloseErrors errors) {
+ if (provider instanceof Closeable) {
+ Closeable closeable = (Closeable) provider;
+ closeable.close(closer, errors);
+ }
+ }
+
@Override public String toString() {
return provider.toString();
}
Index: src/com/google/inject/Injector.java
===================================================================
--- src/com/google/inject/Injector.java (revision 627)
+++ src/com/google/inject/Injector.java Mon Oct 06 13:46:17 BST 2008
@@ -16,6 +16,7 @@
package com.google.inject;
+import com.google.inject.spi.CloseFailedException;
import java.util.List;
import java.util.Map;
@@ -120,4 +121,13 @@
* dependencies ahead of time.
*/
<T> T getInstance(Class<T> type);
+
+ /**
+ * Closes down any singleton resources in this injector by applying any bound
+ * {@link com.google.inject.spi.Closer} strategy implementations to the singleton objects.
+ *
+ * Typically all objects that can be will be closed and a single exception will be thrown
+ * indicating all of the exceptions that occurred while closing all of the resources.
+ */
+ void close() throws CloseFailedException;
}
Index: test/com/google/inject/CloseTest.java
===================================================================
--- test/com/google/inject/CloseTest.java Mon Oct 06 13:37:11 BST 2008
+++ test/com/google/inject/CloseTest.java Mon Oct 06 13:37:11 BST 2008
@@ -0,0 +1,69 @@
+/**
+ * Copyright (C) 2006 Google Inc.
+ *
+ * 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 com.google.inject;
+
+import com.google.inject.spi.Closer;
+import junit.framework.TestCase;
+
+/**
+ * @author james.strachan@gmail.com (James Strachan)
+ */
+public class CloseTest extends TestCase {
+
+ public void testClosing() throws Exception {
+ final MyCloser counter = new MyCloser();
+
+ Injector injector = Guice.createInjector(new AbstractModule() {
+ protected void configure() {
+ bind(Foo.class);
+ bind(MyCloser.class).toInstance(counter);
+ }
+ });
+
+ Foo foo = injector.getInstance(Key.get(Foo.class));
+ foo.foo();
+ assertTrue(foo.invoked);
+
+ foo = injector.getInstance(Foo.class);
+ foo.foo();
+ assertTrue(foo.invoked);
+
+ injector.close();
+
+ assertEquals(1, counter.count);
+ assertSame(foo, counter.closeObject);
+ }
+
+ @Singleton
+ static class Foo {
+ boolean invoked;
+ public void foo() {
+ invoked = true;
+ }
+ }
+
+ static class MyCloser implements Closer {
+
+ int count;
+ Object closeObject;
+
+ public void close(Object object) throws Throwable {
+ count++;
+ this.closeObject = object;
+ }
+ }
+}
\ No newline at end of file
Index: build.xml
===================================================================
--- build.xml (revision 627)
+++ build.xml Sat Oct 04 10:36:05 BST 2008
@@ -16,7 +16,8 @@
<mkdir dir="${build.dir}/dist"/>
<jarjar jarfile="${build.dir}/dist/guice-${version}.jar"
manifest="${build.dir}/META-INF/MANIFEST.MF">
- <fileset dir="${build.dir}/classes"/>
+ <fileset dir="${build.dir}/classes"/>
+ <fileset dir="${build.dir}/../extensions/multibindings/build/classes"/>
<zipfileset src="lib/build/cglib-2.2.jar"/>
<zipfileset src="lib/build/asm-3.1.jar"/>
<zipfileset src="lib/build/google-collect-snapshot-20080530.jar"/>
@@ -32,6 +33,7 @@
<ant antfile="servlet/build.xml" target="distjars" inheritAll="false"/>
<ant antfile="spring/build.xml" target="distjars" inheritAll="false"/>
<ant antfile="struts2/plugin/build.xml" target="distjars" inheritAll="false"/>
+ <ant antfile="jsr250/build.xml" target="distjars" inheritAll="false"/>
<ant antfile="extensions/assistedinject/build.xml" target="distjars" inheritAll="false"/>
<ant antfile="extensions/throwingproviders/build.xml" target="distjars" inheritAll="false"/>
<ant antfile="extensions/multibindings/build.xml" target="distjars" inheritAll="false"/>
@@ -47,6 +49,9 @@
<fileset dir="struts2/plugin/build" includes="*.jar"/>
</copy>
<copy toDir="${build.dir}/dist">
+ <fileset dir="jsr250/build" includes="*.jar"/>
+ </copy>
+ <copy toDir="${build.dir}/dist">
<fileset dir="extensions/assistedinject/build" includes="*.jar"/>
</copy>
<copy toDir="${build.dir}/dist">
@@ -92,6 +97,7 @@
<pathelement location="lib/build/servlet-api-2.5.jar"/>
<pathelement location="lib/build/easymock.jar"/>
<pathelement location="lib/build/google-collect-snapshot-20080530.jar"/>
+ <pathelement location="lib/build/jsr250-api-1.0.jar"/>
</classpath>
<arg value="com.google.inject.AllTests"/>
<syspropertyset>
@@ -112,6 +118,7 @@
<pathelement location="${src.dir}"/>
<pathelement location="${servlet.src.dir}"/>
<pathelement location="${spring.src.dir}"/>
+ <pathelement location="${jsr250.src.dir}"/>
<pathelement location="${assistedinject.src.dir}"/>
<pathelement location="${throwingproviders.src.dir}"/>
<pathelement location="${multibindings.src.dir}"/>
@@ -132,6 +139,7 @@
description="Remove generated files.">
<ant dir="servlet" antfile="build.xml" target="clean"/>
<ant dir="spring" antfile="build.xml" target="clean"/>
+ <ant dir="jsr250" antfile="build.xml" target="clean"/>
<ant dir="struts2/plugin" antfile="build.xml" target="clean"/>
<ant dir="extensions/assistedinject" antfile="build.xml" target="clean"/>
<ant dir="extensions/throwingproviders" antfile="build.xml" target="clean"/>
Index: src/com/google/inject/matcher/Matchers.java
===================================================================
--- src/com/google/inject/matcher/Matchers.java (revision 627)
+++ src/com/google/inject/matcher/Matchers.java Fri Oct 03 17:44:22 BST 2008
@@ -177,6 +177,84 @@
}
/**
+ * Returns a matcher which matches classes which have a public method annotated
+ * with a given annotation.
+ */
+ public static Matcher<AnnotatedElement> methodAnnotatedWith(
+ final Annotation annotation) {
+ return new MethodAnnotatedWith(annotation);
+ }
+
+ /**
+ * Returns a matcher which matches classes which have a public method annotated
+ * with a given annotation.
+ */
+ public static Matcher<AnnotatedElement> methodAnnotatedWith(
+ final Class<? extends Annotation> annotationType) {
+ return new MethodAnnotatedWith(annotationType);
+ }
+
+
+ private static class MethodAnnotatedWith extends AbstractMatcher<AnnotatedElement>
+ implements Serializable {
+ private final Class<? extends Annotation> annotationType;
+
+ public MethodAnnotatedWith(Annotation annotation) {
+ checkNotNull(annotation, "annotation");
+ this.annotationType = annotation.annotationType();
+ checkForRuntimeRetention(annotationType);
+ }
+
+ public MethodAnnotatedWith(Class<? extends Annotation> annotationType) {
+ checkNotNull(annotationType, "annotationType");
+ this.annotationType = annotationType;
+ checkForRuntimeRetention(annotationType);
+ }
+
+ public boolean matches(AnnotatedElement element) {
+ if (element instanceof Class) {
+ Class type = (Class) element;
+ if (matchesClass(type)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ protected boolean matchesClass(Class type) {
+ Method[] methods = type.getDeclaredMethods();
+ for (Method method : methods) {
+ Annotation fromElement = method.getAnnotation(annotationType);
+ if (fromElement != null) {
+ return true;
+ }
+ }
+ if (!Object.class.equals(type)) {
+ Class superclass = type.getSuperclass();
+ if (superclass != null) {
+ return matchesClass(superclass);
+ }
+ }
+ return false;
+ }
+
+ @Override public boolean equals(Object other) {
+ return other instanceof MethodAnnotatedWith
+ && ((MethodAnnotatedWith) other).annotationType.equals(annotationType);
+ }
+
+ @Override public int hashCode() {
+ return 37 * annotationType.hashCode();
+ }
+
+ @Override public String toString() {
+ return "methodAnnotatedWith(" + annotationType + ")";
+ }
+
+ private static final long serialVersionUID = 0;
+ }
+
+ /**
* Returns a matcher which matches subclasses of the given type (as well as
* the given type).
*/
Index: src/com/google/inject/ProxyFactory.java
===================================================================
--- src/com/google/inject/ProxyFactory.java (revision 627)
+++ src/com/google/inject/ProxyFactory.java Fri Oct 03 16:43:32 BST 2008
@@ -28,6 +28,7 @@
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
+import java.lang.reflect.AccessibleObject;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
@@ -38,6 +39,8 @@
import net.sf.cglib.reflect.FastClass;
import net.sf.cglib.reflect.FastConstructor;
import org.aopalliance.intercept.MethodInterceptor;
+import org.aopalliance.intercept.ConstructorInterceptor;
+import org.aopalliance.intercept.ConstructorInvocation;
/**
* Proxies classes applying interceptors to methods as specified in
@@ -48,10 +51,12 @@
class ProxyFactory implements ConstructionProxyFactory {
final List<MethodAspect> methodAspects;
+ final List<ConstructorAspect> constructorAspects;
final ConstructionProxyFactory defaultFactory;
- ProxyFactory(List<MethodAspect> methodAspects) {
+ ProxyFactory(List<MethodAspect> methodAspects, List<ConstructorAspect> constructorAspects) {
this.methodAspects = methodAspects;
+ this.constructorAspects = constructorAspects;
defaultFactory = new DefaultConstructionProxyFactory();
}
@@ -83,7 +88,7 @@
}
}
if (applicableAspects.isEmpty()) {
- return defaultFactory.get(errors, injectionPoint);
+ return wrapConstructorProxy(defaultFactory.get(errors, injectionPoint));
}
// Get list of methods from cglib.
@@ -116,7 +121,7 @@
}
if (!anyMatched) {
// not test-covered
- return defaultFactory.get(errors, injectionPoint);
+ return wrapConstructorProxy(defaultFactory.get(errors, injectionPoint));
}
// Create callbacks.
@@ -150,7 +155,7 @@
// Store callbacks.
Enhancer.registerStaticCallbacks(proxied, callbacks);
- return createConstructionProxy(proxied, injectionPoint);
+ return wrapConstructorProxy(createConstructionProxy(proxied, injectionPoint));
}
/**
@@ -169,15 +174,76 @@
public T newInstance(Object... arguments) throws InvocationTargetException {
return (T) fastConstructor.newInstance(arguments);
}
+
public InjectionPoint getInjectionPoint() {
return injectionPoint;
}
+
public Constructor<T> getConstructor() {
return standardConstructor;
}
};
}
+ private <T> ConstructionProxy<T> wrapConstructorProxy(final ConstructionProxy<?> constructionProxy) {
+ if (constructorAspects.isEmpty()) {
+ return (ConstructionProxy<T>) constructionProxy;
+ }
+ else {
+ // lets wrap the construction proxy to process the interceptors
+ return new ConstructionProxy<T>() {
+ public T newInstance(final Object... arguments) throws InvocationTargetException {
+ @SuppressWarnings("unchecked")
+ T answer = (T) constructionProxy.newInstance(arguments);
+ for (ConstructorAspect aspect : constructorAspects) {
+ List<ConstructorInterceptor> interceptors = aspect.interceptors();
+ for (ConstructorInterceptor interceptor : interceptors) {
+ final T currentValue = answer;
+ ConstructorInvocation invocation = new ConstructorInvocation() {
+ public Constructor getConstructor() {
+ return constructionProxy.getConstructor();
+ }
+
+ public Object[] getArguments() {
+ return arguments;
+ }
+
+ public Object proceed() throws Throwable {
+ return currentValue;
+ }
+
+ public Object getThis() {
+ // TODO
+ return currentValue;
+ }
+
+ public AccessibleObject getStaticPart() {
+ // TODO
+ return null;
+ }
+ };
+ try {
+ answer = (T) interceptor.construct(invocation);
+ }
+ catch (Throwable throwable) {
+ throw new InvocationTargetException(throwable);
+ }
+ }
+ }
+ return answer;
+ }
+
+ public InjectionPoint getInjectionPoint() {
+ return constructionProxy.getInjectionPoint();
+ }
+
+ public Constructor<T> getConstructor() {
+ return (Constructor<T>) constructionProxy.getConstructor();
+ }
+ };
+ }
+ }
+
static class MethodInterceptorsPair {
final Method method;
Index: src/com/google/inject/spi/Closer.java
===================================================================
--- src/com/google/inject/spi/Closer.java Mon Oct 06 13:42:22 BST 2008
+++ src/com/google/inject/spi/Closer.java Mon Oct 06 13:42:22 BST 2008
@@ -0,0 +1,37 @@
+/**
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 com.google.inject.spi;
+
+/**
+ * Represents a strategy for closing an object down such as
+ * using the @PreDestroy lifecycle from JSR 250,
+ * invoking {@link java.io.Closeable#close()}
+ * or using the DisposableBean interface from Spring.
+ *
+ * @version $Revision: 1.1 $
+ */
+public interface Closer {
+ /**
+ * Closes the given object
+ *
+ * @param object the object to be closed
+ * @throws Exception if the close operation caused some exception to occur
+ */
+ void close(Object object) throws Throwable;
+}
Index: jsr250/src/com/google/inject/jsr250/PostConstructInterceptor.java
===================================================================
--- jsr250/src/com/google/inject/jsr250/PostConstructInterceptor.java Mon Oct 06 14:00:35 BST 2008
+++ jsr250/src/com/google/inject/jsr250/PostConstructInterceptor.java Mon Oct 06 14:00:35 BST 2008
@@ -0,0 +1,57 @@
+/**
+ * Copyright (C) 2006 Google Inc.
+ *
+ * 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 com.google.inject.jsr250;
+
+import java.lang.reflect.Method;
+import java.lang.reflect.InvocationTargetException;
+import javax.annotation.PostConstruct;
+import org.aopalliance.intercept.ConstructorInterceptor;
+import org.aopalliance.intercept.ConstructorInvocation;
+
+/**
+ * Supports the {@link PostConstruct} annotation lifecycle from JSR250.
+ * <p>
+ * To install this interceptor call the {@link Jsr250#bind(com.google.inject.Binder)} method
+ * from your module.
+ *
+ * @author james.strachan@gmail.com (James Strachan)
+ * @version $Revision: 1.1 $
+ */
+public class PostConstructInterceptor implements ConstructorInterceptor {
+
+ private AnnotatedMethodCache methodCache = new AnnotatedMethodCache(PostConstruct.class);
+
+ public Object construct(ConstructorInvocation invocation) throws Throwable {
+ Object value = invocation.proceed();
+ if (value != null) {
+ Class<?> type = value.getClass();
+
+ Method method = methodCache.getMethod(type);
+
+ if (method != null) {
+ try {
+ method.invoke(value);
+ }
+ catch (InvocationTargetException e) {
+ throw e.getTargetException();
+ }
+ }
+ }
+ return value;
+ }
+
+}
\ No newline at end of file
Index: spring/src/com/google/inject/spring/InitializingBeanInterceptor.java
===================================================================
--- spring/src/com/google/inject/spring/InitializingBeanInterceptor.java Mon Oct 06 13:51:06 BST 2008
+++ spring/src/com/google/inject/spring/InitializingBeanInterceptor.java Mon Oct 06 13:51:06 BST 2008
@@ -0,0 +1,42 @@
+/**
+ * Copyright (C) 2006 Google Inc.
+ *
+ * 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 com.google.inject.spring;
+
+import org.aopalliance.intercept.ConstructorInterceptor;
+import org.aopalliance.intercept.ConstructorInvocation;
+import org.springframework.beans.factory.InitializingBean;
+
+/**
+ * Invokes the Spring post construction lifecycle on classes implementing {@link InitializingBean}.
+ * <p>
+ * To install this interceptor call the {@link SpringIntegration#bindLifecycle(com.google.inject.Binder)} method
+ * from your module.
+ *
+ * @author james.strachan@gmail.com (James Strachan)
+ * @version $Revision: 1.1 $
+ */
+public class InitializingBeanInterceptor implements ConstructorInterceptor {
+
+ public Object construct(ConstructorInvocation invocation) throws Throwable {
+ Object value = invocation.proceed();
+ if (value instanceof InitializingBean) {
+ InitializingBean bean = (InitializingBean) value;
+ bean.afterPropertiesSet();
+ }
+ return value;
+ }
+}
Index: jsr250/src/com/google/inject/jsr250/package-info.java
===================================================================
--- jsr250/src/com/google/inject/jsr250/package-info.java Fri Oct 03 17:26:31 BST 2008
+++ jsr250/src/com/google/inject/jsr250/package-info.java Fri Oct 03 17:26:31 BST 2008
@@ -0,0 +1,20 @@
+/*
+ * Copyright (C) 2006 Google Inc.
+ *
+ * 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.
+ */
+
+/**
+ * JSR 250 integration
+ */
+package com.google.inject.jsr250;
\ No newline at end of file
Index: jsr250/build.properties
===================================================================
--- jsr250/build.properties Fri Oct 03 17:17:37 BST 2008
+++ jsr250/build.properties Fri Oct 03 17:17:37 BST 2008
@@ -0,0 +1,5 @@
+src.dir=src
+test.dir=test
+build.dir=build
+test.class=com.google.inject.jsr250.Jsr250Test
+module=com.google.inject.jsr250
Index: src/com/google/inject/Binder.java
===================================================================
--- src/com/google/inject/Binder.java (revision 627)
+++ src/com/google/inject/Binder.java Fri Oct 03 16:08:58 BST 2008
@@ -25,6 +25,7 @@
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import org.aopalliance.intercept.MethodInterceptor;
+import org.aopalliance.intercept.ConstructorInterceptor;
/**
* Collects configuration information (primarily <i>bindings</i>) which will be
@@ -200,6 +201,16 @@
Matcher<? super Method> methodMatcher, MethodInterceptor... interceptors);
/**
+ * Binds a constructor interceptor to matching classes.
+ *
+ * @param classMatcher matches classes the interceptor should apply to. For
+ * example: {@code only(Runnable.class)}.
+ * @param interceptors to bind
+ */
+ void bindConstructorInterceptor(Matcher<? super Class<?>> classMatcher,
+ ConstructorInterceptor... interceptors);
+
+ /**
* Binds a scope to an annotation.
*/
void bindScope(Class<? extends Annotation> annotationType, Scope scope);
Index: src/com/google/inject/spi/ModuleWriter.java
===================================================================
--- src/com/google/inject/spi/ModuleWriter.java (revision 627)
+++ src/com/google/inject/spi/ModuleWriter.java Fri Oct 03 16:11:43 BST 2008
@@ -30,6 +30,7 @@
import java.util.List;
import java.util.Set;
import org.aopalliance.intercept.MethodInterceptor;
+import org.aopalliance.intercept.ConstructorInterceptor;
/**
* Creates a Module from a collection of component elements.
@@ -69,6 +70,11 @@
return null;
}
+ public Void visitConstructorInterceptorBinding(ConstructorInterceptorBinding element) {
+ writeBindConstructorInterceptor(binder, element);
+ return null;
+ }
+
public Void visitScopeBinding(ScopeBinding element) {
writeBindScope(binder, element);
return null;
@@ -116,6 +122,13 @@
interceptors.toArray(new MethodInterceptor[interceptors.size()]));
}
+ protected void writeBindConstructorInterceptor(final Binder binder, final ConstructorInterceptorBinding element) {
+ List<ConstructorInterceptor> interceptors = element.getInterceptors();
+ binder.withSource(element.getSource()).bindConstructorInterceptor(
+ element.getClassMatcher(),
+ interceptors.toArray(new ConstructorInterceptor[interceptors.size()]));
+ }
+
protected void writeBindScope(final Binder binder, final ScopeBinding element) {
binder.withSource(element.getSource()).bindScope(
element.getAnnotationType(), element.getScope());
Index: test/com/google/inject/IntegrationTest.java
===================================================================
--- test/com/google/inject/IntegrationTest.java (revision 627)
+++ test/com/google/inject/IntegrationTest.java Fri Oct 03 16:37:08 BST 2008
@@ -18,8 +18,10 @@
import static com.google.inject.matcher.Matchers.any;
import junit.framework.TestCase;
+import org.aopalliance.intercept.ConstructorInterceptor;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
+import org.aopalliance.intercept.ConstructorInvocation;
/**
* @author crazybob@google.com (Bob Lee)
@@ -64,4 +66,36 @@
}
}
+ public void testConstructorInterceptor() throws Exception {
+ final PostConstructInterceptor counter = new PostConstructInterceptor();
+
+ Injector injector = Guice.createInjector(new AbstractModule() {
+ protected void configure() {
+ bind(Foo.class);
+ bindConstructorInterceptor(any(), counter);
-}
+ }
+ });
+
+ Foo foo = injector.getInstance(Key.get(Foo.class));
+ foo.foo();
+ assertTrue(foo.invoked);
+ assertEquals(1, counter.count);
+
+ foo = injector.getInstance(Foo.class);
+ foo.foo();
+ assertTrue(foo.invoked);
+ assertEquals(2, counter.count);
+
+ }
+
+ static class PostConstructInterceptor implements ConstructorInterceptor {
+
+ int count;
+
+ public Object construct(ConstructorInvocation constructorInvocation) throws Throwable {
+ count++;
+ return constructorInvocation.proceed();
+ }
+ }
+
+}
Index: jsr250/src/com/google/inject/jsr250/Jsr250.java
===================================================================
--- jsr250/src/com/google/inject/jsr250/Jsr250.java Mon Oct 06 14:00:35 BST 2008
+++ jsr250/src/com/google/inject/jsr250/Jsr250.java Mon Oct 06 14:00:35 BST 2008
@@ -0,0 +1,43 @@
+/**
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 com.google.inject.jsr250;
+
+import com.google.inject.Binder;
+import com.google.inject.matcher.Matchers;
+import javax.annotation.PostConstruct;
+
+/**
+ * Helper method for installing the JSR 250 lifecycle to a binder
+ *
+ * @version $Revision: 1.1 $
+ */
+public final class Jsr250 {
+
+ /**
+ * Binds the JSR 250 lifecycles to the current binder
+ *
+ * @param binder the binder to install
+ */
+ public static void bind(Binder binder) {
+ binder.bindConstructorInterceptor(Matchers.methodAnnotatedWith(PostConstruct.class),
+ new PostConstructInterceptor());
+
+ binder.bind(PreDestroyCloser.class);
+ }
+}
Index: src/com/google/inject/InjectorBuilder.java
===================================================================
--- src/com/google/inject/InjectorBuilder.java (revision 627)
+++ src/com/google/inject/InjectorBuilder.java Mon Oct 06 13:46:35 BST 2008
@@ -30,6 +30,7 @@
import com.google.inject.spi.Element;
import com.google.inject.spi.Elements;
import com.google.inject.spi.InjectionPoint;
+import com.google.inject.spi.CloseFailedException;
import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -321,5 +322,9 @@
throw new UnsupportedOperationException(
"Injector.getInstance(Class<T>) is not supported in Stage.TOOL");
}
+ public void close() throws CloseFailedException {
+ throw new UnsupportedOperationException(
+ "Injector.close() is not supported in Stage.TOOL");
- }
-}
+ }
+ }
+}
Index: src/com/google/inject/spi/ElementVisitor.java
===================================================================
--- src/com/google/inject/spi/ElementVisitor.java (revision 627)
+++ src/com/google/inject/spi/ElementVisitor.java Fri Oct 03 16:06:50 BST 2008
@@ -38,6 +38,11 @@
V visitInterceptorBinding(InterceptorBinding interceptorBinding);
/**
+ * Visit a registration of constructor interceptors for matching classes.
+ */
+ V visitConstructorInterceptorBinding(ConstructorInterceptorBinding constructorInterceptorBinding);
+
+ /**
* Visit a registration of a scope annotation with the scope that implements it.
*/
V visitScopeBinding(ScopeBinding scopeBinding);
Index: servlet/src/com/google/inject/servlet/GuiceServletContextListener.java
===================================================================
--- servlet/src/com/google/inject/servlet/GuiceServletContextListener.java (revision 627)
+++ servlet/src/com/google/inject/servlet/GuiceServletContextListener.java Mon Oct 06 14:29:32 BST 2008
@@ -17,6 +17,7 @@
package com.google.inject.servlet;
import com.google.inject.Injector;
+import com.google.inject.spi.CloseFailedException;
import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
@@ -39,6 +40,16 @@
public void contextDestroyed(ServletContextEvent servletContextEvent) {
ServletContext servletContext = servletContextEvent.getServletContext();
+ Object value = servletContext.getAttribute(INJECTOR_NAME);
+ if (value instanceof Injector) {
+ Injector injector = (Injector) value;
+ try {
+ injector.close();
+ }
+ catch (CloseFailedException e) {
+ servletContext.log("Failed to close injector. Reason: " + e, e);
+ }
+ }
servletContext.removeAttribute(INJECTOR_NAME);
}
Index: spring/src/com/google/inject/spring/SpringIntegration.java
===================================================================
--- spring/src/com/google/inject/spring/SpringIntegration.java (revision 627)
+++ spring/src/com/google/inject/spring/SpringIntegration.java Mon Oct 06 13:51:06 BST 2008
@@ -20,9 +20,11 @@
import com.google.inject.Binder;
import com.google.inject.Inject;
import com.google.inject.Provider;
+import com.google.inject.matcher.Matchers;
import com.google.inject.name.Names;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.ListableBeanFactory;
+import org.springframework.beans.factory.InitializingBean;
/**
* Integrates Guice with Spring.
@@ -32,7 +34,19 @@
public class SpringIntegration {
private SpringIntegration() {}
+
/**
+ * Binds the Spring lifecycles to the current binder
+ *
+ * @param binder the binder to install
+ */
+ public static void bindLifecycle(Binder binder) {
+ binder.bindConstructorInterceptor(Matchers.subclassesOf(InitializingBean.class),
+ new InitializingBeanInterceptor());
+ binder.bind(DisposableBeanCloser.class);
+ }
+
+ /**
* Creates a provider which looks up objects from Spring using the given name.
* Expects a binding to {@link
* org.springframework.beans.factory.BeanFactory}. Example usage:
Index: build.properties
===================================================================
--- build.properties (revision 627)
+++ build.properties Fri Oct 03 17:21:04 BST 2008
@@ -3,6 +3,7 @@
test.dir=test
servlet.src.dir=servlet/src
spring.src.dir=spring/src
+jsr250.src.dir=jsr250/src
assistedinject.src.dir=extensions/assistedinject/src
commands.src.dir=extensions/commands/src
throwingproviders.src.dir=extensions/throwingproviders/src
@@ -12,6 +13,7 @@
com.google.inject.matcher,com.google.inject.servlet,com.google.inject.name,\
com.google.inject.tools.jmx,com.google.inject.binder,com.google.inject.jndi,\
com.google.inject.spring,\
+ com.google.inject.jsr250,\
com.google.inject.assistedinject,\
com.google.inject.throwingproviders,\
com.google.inject.multibindings,\
Index: src/com/google/inject/AbstractProcessor.java
===================================================================
--- src/com/google/inject/AbstractProcessor.java (revision 627)
+++ src/com/google/inject/AbstractProcessor.java Fri Oct 03 16:09:58 BST 2008
@@ -26,6 +26,7 @@
import com.google.inject.spi.ScopeBinding;
import com.google.inject.spi.StaticInjectionRequest;
import com.google.inject.spi.TypeConverterBinding;
+import com.google.inject.spi.ConstructorInterceptorBinding;
import java.util.Iterator;
import java.util.List;
@@ -70,6 +71,10 @@
return false;
}
+ public Boolean visitConstructorInterceptorBinding(ConstructorInterceptorBinding constructorInterceptorBinding) {
+ return false;
+ }
+
public Boolean visitScopeBinding(ScopeBinding scopeBinding) {
return false;
}
Index: spring/test/com/google/inject/spring/LifecycleTest.java
===================================================================
--- spring/test/com/google/inject/spring/LifecycleTest.java Mon Oct 06 13:53:23 BST 2008
+++ spring/test/com/google/inject/spring/LifecycleTest.java Mon Oct 06 13:53:23 BST 2008
@@ -0,0 +1,63 @@
+/**
+ * Copyright (C) 2006 Google Inc.
+ *
+ * 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 com.google.inject.spring;
+
+import com.google.inject.AbstractModule;
+import com.google.inject.CreationException;
+import com.google.inject.Guice;
+import com.google.inject.Injector;
+import com.google.inject.Singleton;
+import com.google.inject.spi.CloseFailedException;
+import junit.framework.TestCase;
+import org.springframework.beans.factory.DisposableBean;
+import org.springframework.beans.factory.InitializingBean;
+
+/** @author james.strachan@gmail.com (James Strachan) */
+public class LifecycleTest extends TestCase {
+
+ public void testBeanInitialised() throws CreationException, CloseFailedException {
+ Injector injector = Guice.createInjector(new AbstractModule() {
+ protected void configure() {
+ SpringIntegration.bindLifecycle(binder());
+
+ bind(MyBean.class).in(Singleton.class);
+ }
+ });
+
+ MyBean bean = injector.getInstance(MyBean.class);
+ assertNotNull("Should have instantiated the bean", bean);
+ assertTrue("Should have properties set on bean", bean.propertiesSet);
+
+ assertFalse("Should not be destroyed yet", bean.destroyed);
+ injector.close();
+
+ assertTrue("Should have destroyed the bean", bean.destroyed);
+ }
+
+ static class MyBean implements InitializingBean, DisposableBean {
+ public boolean propertiesSet = false;
+ public boolean destroyed;
+
+ public void afterPropertiesSet() throws Exception {
+ propertiesSet = true;
+ }
+
+ public void destroy() throws Exception {
+ destroyed = true;
+ }
+ }
+}
\ No newline at end of file
Index: jsr250/build.xml
===================================================================
--- jsr250/build.xml Fri Oct 03 17:16:44 BST 2008
+++ jsr250/build.xml Fri Oct 03 17:16:44 BST 2008
@@ -0,0 +1,22 @@
+<?xml version="1.0"?>
+
+<project name="guice-jsr250" basedir="." default="jar">
+
+ <import file="../common.xml"/>
+
+ <path id="compile.classpath">
+ <fileset dir="../lib" includes="*.jar"/>
+ <fileset dir="../lib/build" includes="*.jar"/>
+ <fileset dir="../build/dist" includes="*.jar"/>
+ </path>
+
+ <target name="jar" depends="compile, manifest"
+ description="Build jar.">
+ <mkdir dir="${build.dir}"/>
+ <jar destfile="${build.dir}/${ant.project.name}-${version}.jar"
+ manifest="${build.dir}/META-INF/MANIFEST.MF">
+ <fileset dir="${build.dir}/classes"/>
+ </jar>
+ </target>
+
+</project>
Index: src/com/google/inject/spi/Closeable.java
===================================================================
--- src/com/google/inject/spi/Closeable.java Mon Oct 06 11:38:53 BST 2008
+++ src/com/google/inject/spi/Closeable.java Mon Oct 06 11:38:53 BST 2008
@@ -0,0 +1,28 @@
+/**
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 com.google.inject.spi;
+
+/**
+ * Represents a scope or provider which can be closed
+ *
+ * @version $Revision: 1.1 $
+ */
+public interface Closeable {
+ void close(Closer closer, CloseErrors errors);
+}
Index: src/com/google/inject/spi/Elements.java
===================================================================
--- src/com/google/inject/spi/Elements.java (revision 627)
+++ src/com/google/inject/spi/Elements.java Fri Oct 03 16:06:50 BST 2008
@@ -40,6 +40,7 @@
import java.util.Collections;
import java.util.List;
import java.util.Set;
+import org.aopalliance.intercept.ConstructorInterceptor;
import org.aopalliance.intercept.MethodInterceptor;
/**
@@ -134,6 +135,12 @@
elements.add(new InterceptorBinding(getSource(), classMatcher, methodMatcher, interceptors));
}
+ public void bindConstructorInterceptor(
+ Matcher<? super Class<?>> classMatcher,
+ ConstructorInterceptor... interceptors) {
+ elements.add(new ConstructorInterceptorBinding(getSource(), classMatcher, interceptors));
+ }
+
public void bindScope(Class<? extends Annotation> annotationType, Scope scope) {
elements.add(new ScopeBinding(getSource(), annotationType, scope));
}
Index: src/com/google/inject/spi/DefaultElementVisitor.java
===================================================================
--- src/com/google/inject/spi/DefaultElementVisitor.java (revision 627)
+++ src/com/google/inject/spi/DefaultElementVisitor.java Fri Oct 03 16:12:12 BST 2008
@@ -48,6 +48,10 @@
return visitElement(command);
}
+ public V visitConstructorInterceptorBinding(ConstructorInterceptorBinding command) {
+ return visitElement(command);
+ }
+
public V visitScopeBinding(ScopeBinding command) {
return visitElement(command);
}
Index: src/com/google/inject/ConstructorAspect.java
===================================================================
--- src/com/google/inject/ConstructorAspect.java Sat Oct 04 13:43:31 BST 2008
+++ src/com/google/inject/ConstructorAspect.java Sat Oct 04 13:43:31 BST 2008
@@ -0,0 +1,47 @@
+/**
+ * Copyright (C) 2006 Google Inc.
+ *
+ * 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 com.google.inject;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import com.google.inject.matcher.Matcher;
+import java.util.List;
+import org.aopalliance.intercept.ConstructorInterceptor;
+
+/**
+ * Ties a matcher to a constructor interceptor.
+ *
+ * @author james.strachan@gmail.com (James Strachan)
+ */
+class ConstructorAspect {
+
+ final Matcher<? super Class<?>> classMatcher;
+ final List<ConstructorInterceptor> interceptors;
+
+ ConstructorAspect(Matcher<? super Class<?>> classMatcher,
+ List<ConstructorInterceptor> interceptors) {
+ this.classMatcher = checkNotNull(classMatcher, "class matcher");
+ this.interceptors = checkNotNull(interceptors, "interceptors");
+ }
+
+ boolean matches(Class<?> clazz) {
+ return classMatcher.matches(clazz);
+ }
+
+ List<ConstructorInterceptor> interceptors() {
+ return interceptors;
+ }
+}
\ No newline at end of file
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment