Skip to content

Commit

Permalink
✨ 🐲 TypeSugar to get generic class #253
Browse files Browse the repository at this point in the history
  • Loading branch information
trydofor committed Jun 11, 2024
1 parent 4e20272 commit be43862
Show file tree
Hide file tree
Showing 11 changed files with 320 additions and 8 deletions.
1 change: 1 addition & 0 deletions WingsBoot.t.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ Use `t.md` as local [Test Management](https://www.jetbrains.com/help/idea/test-m
* 11032 WingsReorderEnableTest: configed Order/Ordered
* 11033 ThisLazyCglibTest: thisLazy with cglib
* 11034 ThisLazyProxyTest: thisLazy with default jdk proxy
* 11035 TypedClassTest: ResolvableType sugar

## 12 Faceless

Expand Down
2 changes: 1 addition & 1 deletion observe/docs
16 changes: 16 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@
<retrofit.version>2.9.0</retrofit.version> <!-- https://github.com/square/retrofit/tags -->
<allure.version>2.25.0</allure.version> <!-- https://github.com/allure-framework/allure-java/releases -->
<druid.version>1.2.21</druid.version> <!-- https://github.com/alibaba/druid/releases -->
<jmh.version>1.37</jmh.version> <!-- https://github.com/alibaba/druid/releases -->
<!-- mvn-build-plugin -->
<flatten-maven-plugin.version>1.6.0</flatten-maven-plugin.version> <!-- https://github.com/mojohaus/flatten-maven-plugin/releases -->
<directory-maven-plugin.version>1.0</directory-maven-plugin.version> <!-- https://github.com/jdcasey/directory-maven-plugin -->
Expand Down Expand Up @@ -504,6 +505,16 @@
<artifactId>druid-spring-boot-starter</artifactId>
<version>${druid.version}</version>
</dependency>
<dependency>
<groupId>org.openjdk.jmh</groupId>
<artifactId>jmh-core</artifactId>
<version>${jmh.version}</version>
</dependency>
<dependency>
<groupId>org.openjdk.jmh</groupId>
<artifactId>jmh-generator-annprocess</artifactId>
<version>${jmh.version}</version>
</dependency>
<!-- do NOT import any BOM -->
</dependencies>
</dependencyManagement>
Expand Down Expand Up @@ -621,6 +632,11 @@
<artifactId>spring-context-indexer</artifactId>
<version>${spring-framework.version}</version>
</path>
<path>
<groupId>org.openjdk.jmh</groupId>
<artifactId>jmh-generator-annprocess</artifactId>
<version>${jmh.version}</version>
</path>
</annotationProcessorPaths>
</configuration>
</plugin>
Expand Down
10 changes: 10 additions & 0 deletions wings/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,16 @@
<artifactId>allure-java-commons</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.openjdk.jmh</groupId>
<artifactId>jmh-core</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.openjdk.jmh</groupId>
<artifactId>jmh-generator-annprocess</artifactId>
<scope>test</scope>
</dependency>
</dependencies>

<build>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
package pro.fessional.wings.silencer.enhance;

import org.jetbrains.annotations.NotNull;
import org.springframework.core.ResolvableType;
import org.springframework.core.convert.TypeDescriptor;
import pro.fessional.mirana.lock.ArrayKey;

import java.lang.reflect.Type;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.OffsetDateTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.util.concurrent.ConcurrentHashMap;

/**
* ResolvableType for Class with Generics with cache,
* 20 times faster than new ResolvableType, TypeDescriptor
*
* @author trydofor
* @since 2024-06-09
*/
public class TypeSugar {

public static final TypeDescriptor StringDescriptor = TypeDescriptor.valueOf(String.class);
public static final TypeDescriptor BooleanDescriptor = TypeDescriptor.valueOf(Boolean.class);
public static final TypeDescriptor IntegerDescriptor = TypeDescriptor.valueOf(Integer.class);
public static final TypeDescriptor LongDescriptor = TypeDescriptor.valueOf(Long.class);
public static final TypeDescriptor DoubleDescriptor = TypeDescriptor.valueOf(Double.class);
public static final TypeDescriptor FloatDescriptor = TypeDescriptor.valueOf(Float.class);
public static final TypeDescriptor BigDecimalDescriptor = TypeDescriptor.valueOf(BigDecimal.class);

public static final TypeDescriptor LocalDateDescriptor = TypeDescriptor.valueOf(LocalDate.class);
public static final TypeDescriptor LocalTimeDescriptor = TypeDescriptor.valueOf(LocalTime.class);
public static final TypeDescriptor LocalDateTimeDescriptor = TypeDescriptor.valueOf(LocalDateTime.class);
public static final TypeDescriptor ZonedDateTimeDescriptor = TypeDescriptor.valueOf(ZonedDateTime.class);
public static final TypeDescriptor OffsetDateTimeDescriptor = TypeDescriptor.valueOf(OffsetDateTime.class);
public static final TypeDescriptor ZoneIdDescriptor = TypeDescriptor.valueOf(ZoneId.class);


//
private static final ConcurrentHashMap<ArrayKey, ResolvableType> CacheResolvable = new ConcurrentHashMap<>();
private static final ConcurrentHashMap<ArrayKey, TypeDescriptor> CacheDescriptor = new ConcurrentHashMap<>();

/**
* by cache
*/
@NotNull
public static TypeDescriptor describe(@NotNull Class<?> clazz, Class<?>... generics) {
ArrayKey key = generics == null || generics.length == 0
? new ArrayKey(clazz)
: new ArrayKey(clazz, generics);
return CacheDescriptor.computeIfAbsent(key, ignore -> describeNew(clazz, generics));
}

/**
* by cache
*/
@NotNull
public static ResolvableType resolve(@NotNull Class<?> clazz, Class<?>... generics) {
ArrayKey key = generics == null || generics.length == 0
? new ArrayKey(clazz)
: new ArrayKey(clazz, generics);
return CacheResolvable.computeIfAbsent(key, ignore -> resolveNew(clazz, generics));
}

/**
* by cache
*/
@NotNull
public static Type type(@NotNull Class<?> clazz, Class<?>... generics) {
return resolve(clazz, generics).getType();
}

/**
* no cache
*/
@NotNull
public static TypeDescriptor describeNew(@NotNull Class<?> clazz, Class<?>... generics) {
return new TypeDescriptor(resolveNew(clazz, generics), null, null);
}

/**
* no cache
*/
@NotNull
public static ResolvableType resolveNew(@NotNull Class<?> clazz, Class<?>... generics) {
if (generics == null || generics.length == 0) return ResolvableType.forClass(clazz);

final int rootCnt = clazz.getTypeParameters().length;
final ResolvableType[] rootArg = new ResolvableType[rootCnt];

int nextIdx = 0;
for (int ri = 0; ri < rootCnt; ri++) {
Class<?> rt = generics[nextIdx++];
int rc = rt.getTypeParameters().length;
nextIdx = resolve(rt, rootArg, ri, rc, generics, nextIdx);
}

return ResolvableType.forClassWithGenerics(clazz, rootArg);
}

private static int resolve(Class<?> rootClz, ResolvableType[] rootArg, int rootIdx, int paraCnt, Class<?>[] nextClz, int nextIdx) {
if (paraCnt <= 0) {
rootArg[rootIdx] = ResolvableType.forClass(rootClz);
}
else {
final ResolvableType[] args = new ResolvableType[paraCnt];
for (int i = 0; i < paraCnt; i++) {
Class<?> root = nextClz[nextIdx++];
int c1 = root.getTypeParameters().length;
nextIdx = resolve(root, args, i, c1, nextClz, nextIdx);
}
rootArg[rootIdx] = ResolvableType.forClassWithGenerics(rootClz, args);
}
return nextIdx;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
package pro.fessional.wings.silencer.enhance;

import org.openjdk.jmh.annotations.Benchmark;
import org.openjdk.jmh.annotations.BenchmarkMode;
import org.openjdk.jmh.annotations.Fork;
import org.openjdk.jmh.annotations.Measurement;
import org.openjdk.jmh.annotations.Mode;
import org.openjdk.jmh.annotations.OutputTimeUnit;
import org.openjdk.jmh.annotations.Scope;
import org.openjdk.jmh.annotations.State;
import org.openjdk.jmh.annotations.Warmup;
import org.springframework.core.ResolvableType;
import org.springframework.core.convert.TypeDescriptor;

import java.io.IOException;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
* <pre>
* Benchmark Mode Cnt Score Error Units
* TypeSugarMain.describeCache thrpt 4 20406.578 ± 4018.606 ops/ms
* TypeSugarMain.describeNew thrpt 4 1240.069 ± 346.185 ops/ms
* TypeSugarMain.describeRaw thrpt 4 1365.260 ± 312.185 ops/ms
* TypeSugarMain.resolveCache thrpt 4 21342.189 ± 5840.158 ops/ms
* TypeSugarMain.resolveNew thrpt 4 1280.143 ± 214.265 ops/ms
* TypeSugarMain.resolveRaw thrpt 4 2061.249 ± 670.345 ops/ms
* </pre>
*
* @author trydofor
* @since 2024-06-09
*/
@Fork(2)
@Warmup(iterations = 1)
@Measurement(iterations = 2)
@BenchmarkMode(Mode.Throughput)
@OutputTimeUnit(TimeUnit.MILLISECONDS)
@State(Scope.Benchmark)
public class TypeSugarMain {

@Benchmark
public void resolveRaw() {
ResolvableType.forClassWithGenerics(Map.class,
ResolvableType.forClassWithGenerics(List.class, Long[].class),
ResolvableType.forClass(String.class)
);
}

@Benchmark
public void resolveNew() {
TypeSugar.resolveNew(Map.class, List.class, List.class, Long[].class, String.class);
}

@Benchmark
public void resolveCache() {
TypeSugar.resolve(Map.class, List.class, List.class, Long[].class, String.class);
}

@Benchmark
public void describeRaw() {
TypeDescriptor.map(Map.class,
TypeDescriptor.collection(List.class, TypeDescriptor.collection(List.class, TypeDescriptor.valueOf(Long[].class))),
TypeDescriptor.valueOf(String.class)
);
}

@Benchmark
public void describeNew() {
TypeSugar.describeNew(Map.class, List.class, List.class, Long[].class, String.class);
}

@Benchmark
public void describeCache() {
TypeSugar.describe(Map.class, List.class, List.class, Long[].class, String.class);
}


public static void main(String[] args) throws IOException {
org.openjdk.jmh.Main.main(args);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
package pro.fessional.wings.silencer.enhance;

import io.qameta.allure.TmsLink;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.springframework.core.ResolvableType;
import org.springframework.core.convert.TypeDescriptor;

import java.util.List;
import java.util.Map;

/**
* @author trydofor
* @since 2024-06-09
*/
public class TypeSugarTest {

@Test
@TmsLink("C11035")
void test() {

// Map<String, List<Long[]>
var a0 = ResolvableType.forClassWithGenerics(Map.class,
ResolvableType.forClass(String.class),
ResolvableType.forClassWithGenerics(List.class, Long[].class)
);
var a1 = TypeSugar.resolve(Map.class, String.class, List.class, Long[].class);

var a2 = TypeDescriptor.map(Map.class,
TypeDescriptor.valueOf(String.class),
TypeDescriptor.collection(List.class, TypeDescriptor.valueOf(Long[].class))
);
var a3 = TypeSugar.describe(Map.class, String.class, List.class, Long[].class);

Assertions.assertEquals(a0, a1);
Assertions.assertEquals(a2, a3);

// Map<List<Long[]>,String>
var b0 = ResolvableType.forClassWithGenerics(Map.class,
ResolvableType.forClassWithGenerics(List.class, Long[].class),
ResolvableType.forClass(String.class)
);
var b1 = TypeSugar.resolve(Map.class, List.class, Long[].class, String.class);

var b2 = TypeDescriptor.map(Map.class,
TypeDescriptor.collection(List.class, TypeDescriptor.valueOf(Long[].class)),
TypeDescriptor.valueOf(String.class)
);
var b3 = TypeSugar.describe(Map.class, List.class, Long[].class, String.class);

Assertions.assertEquals(b0, b1);
Assertions.assertEquals(b2, b3);

// Map<List<List<Long[]>>,String>
var c0 = ResolvableType.forClassWithGenerics(Map.class,
ResolvableType.forClassWithGenerics(List.class,
ResolvableType.forClassWithGenerics(List.class, Long[].class)
),
ResolvableType.forClass(String.class)
);
var c1 = TypeSugar.resolve(Map.class, List.class, List.class, Long[].class, String.class);

var c2 = TypeDescriptor.map(Map.class,
TypeDescriptor.collection(List.class,
TypeDescriptor.collection(List.class, TypeDescriptor.valueOf(Long[].class))
),
TypeDescriptor.valueOf(String.class)
);
var c3 = TypeSugar.describe(Map.class, List.class, List.class, Long[].class, String.class);

Assertions.assertEquals(c0, c1);
Assertions.assertEquals(c2, c3);

var d0 = TypeSugar.resolve(Map.class, List.class, List.class, Long[].class, String.class);
var d1 = TypeSugar.resolve(Map.class, List.class, List.class, Long[].class, String.class);
var d2 = TypeSugar.describe(Map.class, List.class, List.class, Long[].class, String.class);
var d3 = TypeSugar.describe(Map.class, List.class, List.class, Long[].class, String.class);
Assertions.assertSame(d0, d1);
Assertions.assertSame(d2, d3);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ public Object doubleKill(ProceedingJoinPoint joinPoint) throws Throwable {
final Method method = ((MethodSignature) joinPoint.getSignature()).getMethod();
final DoubleKill doubleKill = method.getAnnotation(DoubleKill.class);

final Object uid = doubleKill.principal() ? TerminalContext.get(false).getUserId() : DefaultUserId.Guest;
final Long uid = doubleKill.principal() ? TerminalContext.get(false).getUserId() : DefaultUserId.Guest;
final Object[] args = joinPoint.getArgs();

final String keyStr = doubleKill.value();
Expand Down
Loading

0 comments on commit be43862

Please sign in to comment.