Skip to content

Commit

Permalink
ObjectWriterProvider & ObjectReaderProvider support cleanUp, for issue
Browse files Browse the repository at this point in the history
  • Loading branch information
wenshao committed Sep 19, 2022
1 parent fa20ff9 commit db92cff
Show file tree
Hide file tree
Showing 3 changed files with 178 additions and 4 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -419,6 +419,51 @@ public boolean unregister(ObjectReaderModule module) {
return modules.remove(module);
}

public void cleanUp(Class objectClass) {
mixInCache.remove(objectClass);
cache.remove(objectClass);
cacheFieldBased.remove(objectClass);
for (ConcurrentHashMap<Long, ObjectReader> tlc : tclHashCaches.values()) {
for (Iterator<Map.Entry<Long, ObjectReader>> it = tlc.entrySet().iterator(); it.hasNext();) {
Map.Entry<Long, ObjectReader> entry = it.next();
ObjectReader reader = entry.getValue();
if (reader.getObjectClass() == objectClass) {
it.remove();
}
}
}
}

public void cleanUp(ClassLoader classLoader) {
for (Iterator<Map.Entry<Class, Class>> it = mixInCache.entrySet().iterator(); it.hasNext();) {
Map.Entry<Class, Class> entry = it.next();
if (entry.getKey().getClassLoader() == classLoader) {
it.remove();
}
}

for (Iterator<Map.Entry<Type, ObjectReader>> it = cache.entrySet().iterator(); it.hasNext();) {
Map.Entry<Type, ObjectReader> entry = it.next();
Type keyType = entry.getKey();
Class<?> keyClass = TypeUtils.getClass(keyType);
if (keyClass != null && keyClass.getClassLoader() == classLoader) {
it.remove();
}
}

for (Iterator<Map.Entry<Type, ObjectReader>> it = cacheFieldBased.entrySet().iterator(); it.hasNext();) {
Map.Entry<Type, ObjectReader> entry = it.next();
Type keyType = entry.getKey();
Class<?> keyClass = TypeUtils.getClass(keyType);
if (keyClass != null && keyClass.getClassLoader() == classLoader) {
it.remove();
}
}

int tclHash = System.identityHashCode(classLoader);
tclHashCaches.remove(tclHash);
}

public ObjectReaderCreator getCreator() {
ObjectReaderCreator contextCreator = JSONFactory.getContextReaderCreator();
if (contextCreator != null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,7 @@
import java.lang.reflect.Type;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

Expand Down Expand Up @@ -274,4 +271,37 @@ public static boolean isNotReferenceDetect(final Class<?> clazz) {
return Arrays.binarySearch(NOT_REFERENCES_TYPE_HASH_CODES, System.identityHashCode(clazz)) >= 0
|| ((clazz.getModifiers() & ENUM) != 0 && clazz.getSuperclass() == Enum.class);
}

public void cleanUp(Class objectClass) {
mixInCache.remove(objectClass);
cache.remove(objectClass);
cacheFieldBased.remove(objectClass);
}

public void cleanUp(ClassLoader classLoader) {
for (Iterator<Map.Entry<Class, Class>> it = mixInCache.entrySet().iterator(); it.hasNext();) {
Map.Entry<Class, Class> entry = it.next();
if (entry.getKey().getClassLoader() == classLoader) {
it.remove();
}
}

for (Iterator<Map.Entry<Type, ObjectWriter>> it = cache.entrySet().iterator(); it.hasNext();) {
Map.Entry<Type, ObjectWriter> entry = it.next();
Type keyType = entry.getKey();
Class<?> keyClass = TypeUtils.getClass(keyType);
if (keyClass != null && keyClass.getClassLoader() == classLoader) {
it.remove();
}
}

for (Iterator<Map.Entry<Type, ObjectWriter>> it = cacheFieldBased.entrySet().iterator(); it.hasNext();) {
Map.Entry<Type, ObjectWriter> entry = it.next();
Type keyType = entry.getKey();
Class<?> keyClass = TypeUtils.getClass(keyType);
if (keyClass != null && keyClass.getClassLoader() == classLoader) {
it.remove();
}
}
}
}
99 changes: 99 additions & 0 deletions core/src/test/java/com/alibaba/fastjson2/issues/Issue783.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
package com.alibaba.fastjson2.issues;

import com.alibaba.fastjson2.JSONFactory;
import com.alibaba.fastjson2.read.ClassLoaderTest;
import com.alibaba.fastjson2.reader.ObjectReader;
import com.alibaba.fastjson2.reader.ObjectReaderProvider;
import com.alibaba.fastjson2.writer.ObjectWriter;
import com.alibaba.fastjson2.writer.ObjectWriterProvider;
import org.apache.commons.io.IOUtils;
import org.junit.jupiter.api.Test;

import java.io.IOException;
import java.io.InputStream;

import static org.junit.jupiter.api.Assertions.assertNotSame;
import static org.junit.jupiter.api.Assertions.assertSame;

public class Issue783 {
@Test
public void test() {
ObjectWriterProvider writerProvider = JSONFactory.getDefaultObjectWriterProvider();
ObjectWriter objectWriter = writerProvider.getObjectWriter(Bean.class);
ObjectWriter objectWriter1 = writerProvider.getObjectWriter(Bean.class);
assertSame(objectWriter, objectWriter1);
writerProvider.cleanUp(Bean.class);
ObjectWriter objectWriter2 = writerProvider.getObjectWriter(Bean.class);
assertNotSame(objectWriter, objectWriter2);
}

@Test
public void test1() {
ObjectReaderProvider readerProvider = JSONFactory.getDefaultObjectReaderProvider();
ObjectReader objectReader = readerProvider.getObjectReader(Bean.class);
ObjectReader objectReader1 = readerProvider.getObjectReader(Bean.class);
assertSame(objectReader, objectReader1);

readerProvider.cleanUp(Bean.class);
ObjectReader objectReader2 = readerProvider.getObjectReader(Bean.class);
assertNotSame(objectReader, objectReader2);
}

public static class Bean {
}

@Test
public void test2() throws Exception {
ClassLoaderTest.ExtClassLoader classLoader = new ClassLoaderTest.ExtClassLoader();
Class objectClass = classLoader.loadClass("com.alibaba.mock.demo.api.Demo");

ObjectWriterProvider writerProvider = JSONFactory.getDefaultObjectWriterProvider();
ObjectWriter objectWriter = writerProvider.getObjectWriter(objectClass);
ObjectWriter objectWriter1 = writerProvider.getObjectWriter(objectClass);
assertSame(objectWriter, objectWriter1);

writerProvider.cleanUp(classLoader);

ObjectWriter objectWriter2 = writerProvider.getObjectWriter(objectClass);
assertNotSame(objectWriter, objectWriter2);
}

@Test
public void test3() throws Exception {
ClassLoaderTest.ExtClassLoader classLoader = new ClassLoaderTest.ExtClassLoader();
Class objectClass = classLoader.loadClass("com.alibaba.mock.demo.api.Demo");

ObjectReaderProvider readerProvider = JSONFactory.getDefaultObjectReaderProvider();
ObjectReader objectReader = readerProvider.getObjectReader(objectClass);
ObjectReader objectReader1 = readerProvider.getObjectReader(objectClass);
assertSame(objectReader, objectReader1);

readerProvider.cleanUp(classLoader);
ObjectReader objectReader2 = readerProvider.getObjectReader(objectClass);
assertNotSame(objectReader, objectReader2);
}

public static class ExtClassLoader
extends ClassLoader {
public ExtClassLoader() throws IOException {
super(Thread.currentThread().getContextClassLoader());

{
byte[] bytes;
InputStream is = Thread.currentThread().getContextClassLoader().getResourceAsStream("external/Demo.clazz");
bytes = IOUtils.toByteArray(is);
is.close();

super.defineClass("com.alibaba.mock.demo.api.Demo", bytes, 0, bytes.length);
}
{
byte[] bytes;
InputStream is = Thread.currentThread().getContextClassLoader().getResourceAsStream("external/MockDemoService.clazz");
bytes = IOUtils.toByteArray(is);
is.close();

super.defineClass("com.alibaba.mock.demo.service.MockDemoService", bytes, 0, bytes.length);
}
}
}
}

0 comments on commit db92cff

Please sign in to comment.