Skip to content

Commit

Permalink
Add a utility class for checking if Guice has enhanced a class (and r…
Browse files Browse the repository at this point in the history
…eturning the unenahnced version).

(Also changes the classname suffix to be a hex string instead of an int, which had previously included a leading negative sign, which was weird.)

Fixes #1340 & fixes #187.

PiperOrigin-RevId: 525256080
  • Loading branch information
sameb authored and Guice Team committed Apr 18, 2023
1 parent 9678847 commit 139e697
Show file tree
Hide file tree
Showing 3 changed files with 116 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -102,8 +102,8 @@ protected AbstractGlueGenerator(Class<?> hostClass, String marker) {

/** Generates a unique name based on the original class name and marker. */
private static String proxyName(String hostName, String marker, int hash) {
int id = ((hash & 0x000FFFFF) | (COUNTER.getAndIncrement() << 20));
String proxyName = hostName + marker + id;
long id = ((hash & 0x000FFFFF) | (COUNTER.getAndIncrement() << 20));
String proxyName = hostName + marker + Long.toHexString(id);
if (proxyName.startsWith("java/") && !ClassDefining.hasPackageAccess()) {
proxyName = '$' + proxyName; // can't define java.* glue in same package
}
Expand Down
51 changes: 51 additions & 0 deletions core/src/com/google/inject/util/Enhanced.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
/*
* Copyright (C) 2023 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.util;

import com.google.inject.internal.BytecodeGen;
import java.util.Optional;
import java.util.regex.Pattern;

/** Utilities for checking if classes are enhanced and/or getting the original un-enhanced class. */
public final class Enhanced {

// The pattern for enhanced classes. Note that the trailing (/.*)? is to support the ANONYMOUS
// classloading option, which uses defineAnonymousClass|defineHiddenClass, which return classes
// suffixed with a trailing "/<suffix>". According to the spec, the suffix can be pretty much
// anything (though in theory it is a hexadecimal value).
private static final Pattern ENHANCED =
Pattern.compile(
".+" + Pattern.quote(BytecodeGen.ENHANCER_BY_GUICE_MARKER) + "[a-f0-9]+(/.*)?$");

private Enhanced() {}

/** Returns true if this is a class that Guice enhanced with AOP functionality. */
public static boolean isEnhanced(Class<?> clazz) {
return ENHANCED.matcher(clazz.getSimpleName()).matches();
}

/**
* If the input class is a class that {@link #isEnhanced} is true for, returns the un-enhanced
* version of the class. Otherwise returns an empty optional.
*/
public static Optional<Class<?>> unenhancedClass(Class<?> clazz) {
if (!isEnhanced(clazz)) {
return Optional.empty();
}
return Optional.of(clazz.getSuperclass());
}
}
63 changes: 63 additions & 0 deletions core/test/com/google/inject/util/EnhancedTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
package com.google.inject.util;

import static com.google.common.truth.Truth.assertThat;

import com.google.inject.AbstractModule;
import com.google.inject.Guice;
import com.google.inject.Injector;
import com.google.inject.matcher.Matchers;
import java.util.Optional;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;

@RunWith(JUnit4.class)
public final class EnhancedTest {
@Test
public void isEnhancedAndUnenhancedClass() {
Injector injector =
Guice.createInjector(
new AbstractModule() {
@Override
protected void configure() {
binder()
.bindInterceptor(
Matchers.only(Foo.class),
Matchers.any(),
new MethodInterceptor() {
@Override
public Object invoke(MethodInvocation i) throws Throwable {
return "intercepted-" + i.proceed();
}
});
bind(Foo.class);
bind(Bar.class);
}
});
Foo foo = injector.getInstance(Foo.class);
Bar bar = injector.getInstance(Bar.class);
// Validate preconditions: foo is intercepted & bar isn't.
assertThat(foo.foo()).isEqualTo("intercepted-foo");
assertThat(bar.bar()).isEqualTo("bar");

// The actual tests.
assertThat(Enhanced.isEnhanced(foo.getClass())).isTrue();
assertThat(Enhanced.unenhancedClass(foo.getClass())).isEqualTo(Optional.of(Foo.class));
assertThat(Enhanced.isEnhanced(bar.getClass())).isFalse();
assertThat(Enhanced.unenhancedClass(bar.getClass())).isEqualTo(Optional.empty());
}

public static class Foo {
public String foo() {
return "foo";
}
}

public static class Bar {
public String bar() {
return "bar";
}
}
}

0 comments on commit 139e697

Please sign in to comment.