blob: 278e4c4d6d1e246af9c0a89daa89454d4068b8f3 [file] [log] [blame]
/*
* 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 freemarker.ext.beans;
import static org.hamcrest.Matchers.*;
import static org.junit.Assert.*;
import java.lang.ref.Reference;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import freemarker.ext.beans.BeansWrapper.MethodAppearanceDecision;
import freemarker.ext.beans.BeansWrapper.MethodAppearanceDecisionInput;
import freemarker.template.Configuration;
import freemarker.template.SimpleObjectWrapper;
import freemarker.template.TemplateDateModel;
import freemarker.template.TemplateHashModel;
import freemarker.template.TemplateModelException;
import freemarker.template.TemplateScalarModel;
import freemarker.template.Version;
import freemarker.template._TemplateAPI;
import junit.framework.TestCase;
public class BeansWrapperSingletonsTest extends TestCase {
public BeansWrapperSingletonsTest(String name) {
super(name);
}
@Override
protected void setUp() throws Exception {
BeansWrapperBuilder.clearInstanceCache(); // otherwise ClassInrospector cache couldn't become cleared in reality
_TemplateAPI.DefaultObjectWrapperFactory_clearInstanceCache();
BeansWrapperBuilder.clearInstanceCache();
}
public void testBeansWrapperFactoryEquals() throws Exception {
assertEquals(Configuration.VERSION_2_3_21, new BeansWrapperBuilder(Configuration.VERSION_2_3_21).getIncompatibleImprovements());
assertEquals(Configuration.VERSION_2_3_0, new BeansWrapperBuilder(Configuration.VERSION_2_3_20).getIncompatibleImprovements());
try {
new BeansWrapperBuilder(new Version(2, 3, 25));
fail("Maybe you need to update this test for the new FreeMarker version");
} catch (IllegalArgumentException e) {
assertThat(e.getMessage(), containsString("upgrade"));
}
BeansWrapperBuilder pa1;
BeansWrapperBuilder pa2;
pa1 = new BeansWrapperBuilder(Configuration.VERSION_2_3_21);
pa2 = new BeansWrapperBuilder(Configuration.VERSION_2_3_21);
assertEquals(pa1, pa2);
pa1.setSimpleMapWrapper(true);
assertNotEquals(pa1, pa2);
assertFalse(pa1.hashCode() == pa2.hashCode());
pa2.setSimpleMapWrapper(true);
assertEquals(pa1, pa2);
assertTrue(pa1.hashCode() == pa2.hashCode());
pa1.setExposeFields(true);
assertNotEquals(pa1, pa2);
assertFalse(pa1.hashCode() == pa2.hashCode());
pa2.setExposeFields(true);
assertEquals(pa1, pa2);
assertTrue(pa1.hashCode() == pa2.hashCode());
pa1.setExposureLevel(0);
assertNotEquals(pa1, pa2);
assertFalse(pa1.hashCode() == pa2.hashCode());
pa2.setExposureLevel(0);
assertEquals(pa1, pa2);
assertTrue(pa1.hashCode() == pa2.hashCode());
pa1.setExposureLevel(1);
assertNotEquals(pa1, pa2);
assertFalse(pa1.hashCode() == pa2.hashCode());
pa2.setExposureLevel(1);
assertEquals(pa1, pa2);
assertTrue(pa1.hashCode() == pa2.hashCode());
pa1.setDefaultDateType(TemplateDateModel.DATE);
assertNotEquals(pa1, pa2);
pa2.setDefaultDateType(TemplateDateModel.DATE);
assertEquals(pa1, pa2);
assertTrue(pa1.hashCode() == pa2.hashCode());
pa1.setStrict(true);
assertNotEquals(pa1, pa2);
assertFalse(pa1.hashCode() == pa2.hashCode());
pa2.setStrict(true);
assertEquals(pa1, pa2);
assertTrue(pa1.hashCode() == pa2.hashCode());
pa1.setUseModelCache(true);
assertNotEquals(pa1, pa2);
assertFalse(pa1.hashCode() == pa2.hashCode());
pa2.setUseModelCache(true);
assertEquals(pa1, pa2);
assertTrue(pa1.hashCode() == pa2.hashCode());
AlphabeticalMethodSorter ms = new AlphabeticalMethodSorter(true);
pa1.setMethodSorter(ms);
assertNotEquals(pa1, pa2);
pa2.setMethodSorter(ms);
assertEquals(pa1, pa2);
assertTrue(pa1.hashCode() == pa2.hashCode());
MethodAppearanceFineTuner maft = new MethodAppearanceFineTuner() {
public void process(MethodAppearanceDecisionInput in, MethodAppearanceDecision out) { }
};
pa1.setMethodAppearanceFineTuner(maft);
assertNotEquals(pa1, pa2);
pa2.setMethodAppearanceFineTuner(maft);
assertEquals(pa1, pa2);
assertTrue(pa1.hashCode() == pa2.hashCode());
}
public void testBeansWrapperFactoryProducts() throws Exception {
List<BeansWrapper> hardReferences = new LinkedList<BeansWrapper>();
assertEquals(0, getBeansWrapperInstanceCacheSize());
{
BeansWrapper bw = getBeansWrapperWithSetting(Configuration.VERSION_2_3_19, true);
assertEquals(1, getBeansWrapperInstanceCacheSize());
assertSame(bw.getClass(), BeansWrapper.class);
assertEquals(Configuration.VERSION_2_3_0, bw.getIncompatibleImprovements());
assertTrue(bw.isWriteProtected());
assertTrue(bw.isSimpleMapWrapper());
assertTrue(bw.wrap(new HashMap()) instanceof SimpleMapModel);
assertFalse(bw.isStrict());
assertFalse(bw.getUseCache());
assertEquals(TemplateDateModel.UNKNOWN, bw.getDefaultDateType());
assertSame(bw, bw.getOuterIdentity());
assertTrue(bw.isClassIntrospectionCacheRestricted());
assertNull(bw.getMethodAppearanceFineTuner());
assertNull(bw.getMethodSorter());
try {
bw.setExposeFields(true); // can't modify the settings of a (potential) singleton
fail();
} catch (IllegalStateException e) {
assertThat(e.getMessage(), containsString("modify"));
}
assertSame(bw, getBeansWrapperWithSetting(Configuration.VERSION_2_3_20, true));
assertSame(bw, getBeansWrapperWithSetting(Configuration.VERSION_2_3_0, true));
assertEquals(1, getBeansWrapperInstanceCacheSize());
BeansWrapperBuilder factory = new BeansWrapperBuilder(new Version(2, 3, 5));
factory.setSimpleMapWrapper(true);
assertSame(bw, factory.build());
assertEquals(1, getBeansWrapperInstanceCacheSize());
hardReferences.add(bw);
}
{
BeansWrapper bw = getBeansWrapperWithSetting(Configuration.VERSION_2_3_21, true);
assertEquals(2, getBeansWrapperInstanceCacheSize());
assertSame(bw.getClass(), BeansWrapper.class);
assertEquals(Configuration.VERSION_2_3_21, bw.getIncompatibleImprovements());
assertTrue(bw.isWriteProtected());
assertTrue(bw.isSimpleMapWrapper());
assertTrue(bw.wrap(new HashMap()) instanceof SimpleMapModel);
assertTrue(bw.isClassIntrospectionCacheRestricted());
assertNull(bw.getMethodAppearanceFineTuner());
assertNull(bw.getMethodSorter());
BeansWrapperBuilder factory = new BeansWrapperBuilder(Configuration.VERSION_2_3_21);
factory.setSimpleMapWrapper(true);
assertSame(bw, factory.build());
assertEquals(2, getBeansWrapperInstanceCacheSize());
hardReferences.add(bw);
}
{
// Again... same as the very first
BeansWrapper bw = getBeansWrapperWithSetting(Configuration.VERSION_2_3_19, true);
assertEquals(2, getBeansWrapperInstanceCacheSize());
assertEquals(Configuration.VERSION_2_3_0, bw.getIncompatibleImprovements());
}
{
BeansWrapper bw = getBeansWrapperWithSetting(Configuration.VERSION_2_3_19, false);
assertEquals(3, getBeansWrapperInstanceCacheSize());
assertSame(bw.getClass(), BeansWrapper.class);
assertEquals(Configuration.VERSION_2_3_0, bw.getIncompatibleImprovements());
assertTrue(bw.isWriteProtected());
assertFalse(bw.isSimpleMapWrapper());
assertTrue(bw.wrap(new HashMap()) instanceof MapModel);
assertSame(bw, getBeansWrapperWithSetting(Configuration.VERSION_2_3_20, false));
assertSame(bw, getBeansWrapperWithSetting(Configuration.VERSION_2_3_0, false));
assertSame(bw, new BeansWrapperBuilder(new Version(2, 3, 5)).build());
assertEquals(3, getBeansWrapperInstanceCacheSize());
hardReferences.add(bw);
}
{
BeansWrapper bw = getBeansWrapperWithSetting(Configuration.VERSION_2_3_21, false);
assertEquals(4, getBeansWrapperInstanceCacheSize());
assertSame(bw.getClass(), BeansWrapper.class);
assertEquals(Configuration.VERSION_2_3_21, bw.getIncompatibleImprovements());
assertTrue(bw.isWriteProtected());
assertFalse(bw.isSimpleMapWrapper());
assertTrue(bw.wrap(new HashMap()) instanceof MapModel);
assertSame(bw, new BeansWrapperBuilder(Configuration.VERSION_2_3_21).build());
assertEquals(4, getBeansWrapperInstanceCacheSize());
hardReferences.add(bw);
}
{
// Again... same as earlier
BeansWrapper bw = getBeansWrapperWithSetting(Configuration.VERSION_2_3_21, true);
assertEquals(Configuration.VERSION_2_3_21, bw.getIncompatibleImprovements());
assertTrue(bw.isSimpleMapWrapper());
assertEquals(4, getBeansWrapperInstanceCacheSize());
}
{
BeansWrapperBuilder factory = new BeansWrapperBuilder(Configuration.VERSION_2_3_19);
factory.setExposureLevel(BeansWrapper.EXPOSE_PROPERTIES_ONLY);
BeansWrapper bw = factory.build();
BeansWrapper bw2 = factory.build();
assertEquals(5, getBeansWrapperInstanceCacheSize());
assertSame(bw, bw2);
assertSame(bw.getClass(), BeansWrapper.class);
assertEquals(Configuration.VERSION_2_3_0, bw.getIncompatibleImprovements());
assertTrue(bw.isWriteProtected());
assertFalse(bw.isSimpleMapWrapper());
assertTrue(bw.wrap(new HashMap()) instanceof MapModel);
assertEquals(BeansWrapper.EXPOSE_PROPERTIES_ONLY, bw.getExposureLevel());
assertFalse(bw.isStrict());
assertEquals(TemplateDateModel.UNKNOWN, bw.getDefaultDateType());
assertSame(bw, bw.getOuterIdentity());
hardReferences.add(bw);
}
{
BeansWrapperBuilder factory = new BeansWrapperBuilder(Configuration.VERSION_2_3_19);
factory.setExposeFields(true);
BeansWrapper bw = factory.build();
BeansWrapper bw2 = factory.build();
assertEquals(6, getBeansWrapperInstanceCacheSize());
assertSame(bw, bw2);
assertSame(bw.getClass(), BeansWrapper.class);
assertEquals(Configuration.VERSION_2_3_0, bw.getIncompatibleImprovements());
assertTrue(bw.isWriteProtected());
assertFalse(bw.isSimpleMapWrapper());
assertTrue(bw.wrap(new HashMap()) instanceof MapModel);
assertTrue(bw.isExposeFields());
hardReferences.add(bw);
}
{
BeansWrapperBuilder factory = new BeansWrapperBuilder(Configuration.VERSION_2_3_19);
factory.setStrict(true);
factory.setDefaultDateType(TemplateDateModel.DATETIME);
factory.setOuterIdentity(new SimpleObjectWrapper());
BeansWrapper bw = factory.build();
assertEquals(7, getBeansWrapperInstanceCacheSize());
assertTrue(bw.isStrict());
assertEquals(TemplateDateModel.DATETIME, bw.getDefaultDateType());
assertSame(SimpleObjectWrapper.class, bw.getOuterIdentity().getClass());
hardReferences.add(bw);
}
// Effect of reference and cache clearings:
{
BeansWrapper bw1 = new BeansWrapperBuilder(Configuration.VERSION_2_3_21).build();
assertEquals(7, getBeansWrapperInstanceCacheSize());
assertEquals(7, getBeansWrapperNonClearedInstanceCacheSize());
clearBeansWrapperInstanceCacheReferences(false);
assertEquals(7, getBeansWrapperInstanceCacheSize());
assertEquals(0, getBeansWrapperNonClearedInstanceCacheSize());
BeansWrapper bw2 = new BeansWrapperBuilder(Configuration.VERSION_2_3_21).build();
assertNotSame(bw1, bw2);
assertEquals(7, getBeansWrapperInstanceCacheSize());
assertEquals(1, getBeansWrapperNonClearedInstanceCacheSize());
assertSame(bw2, new BeansWrapperBuilder(Configuration.VERSION_2_3_21).build());
assertEquals(1, getBeansWrapperNonClearedInstanceCacheSize());
clearBeansWrapperInstanceCacheReferences(true);
BeansWrapper bw3 = new BeansWrapperBuilder(Configuration.VERSION_2_3_21).build();
assertNotSame(bw2, bw3);
assertEquals(1, getBeansWrapperInstanceCacheSize());
assertEquals(1, getBeansWrapperNonClearedInstanceCacheSize());
}
{
BeansWrapperBuilder factory = new BeansWrapperBuilder(Configuration.VERSION_2_3_19);
factory.setUseModelCache(true);
BeansWrapper bw = factory.build();
assertTrue(bw.getUseCache());
assertEquals(2, getBeansWrapperInstanceCacheSize());
hardReferences.add(bw);
}
assertTrue(hardReferences.size() != 0); // just to save it from GC until this line
}
private BeansWrapper getBeansWrapperWithSetting(Version ici, boolean simpleMapWrapper) {
BeansWrapperBuilder f = new BeansWrapperBuilder(ici);
f.setSimpleMapWrapper(simpleMapWrapper);
return f.build();
}
public void testMultipleTCCLs() {
List<BeansWrapper> hardReferences = new LinkedList<BeansWrapper>();
assertEquals(0, getBeansWrapperInstanceCacheSize());
BeansWrapper bw1 = new BeansWrapperBuilder(Configuration.VERSION_2_3_19).build();
assertEquals(1, getBeansWrapperInstanceCacheSize());
hardReferences.add(bw1);
ClassLoader oldTCCL = Thread.currentThread().getContextClassLoader();
// Doesn't mater what, just be different from oldTCCL:
ClassLoader newTCCL = oldTCCL == null ? this.getClass().getClassLoader() : null;
BeansWrapper bw2;
Thread.currentThread().setContextClassLoader(newTCCL);
try {
bw2 = new BeansWrapperBuilder(Configuration.VERSION_2_3_19).build();
assertEquals(2, getBeansWrapperInstanceCacheSize());
hardReferences.add(bw2);
assertNotSame(bw1, bw2);
assertSame(bw2, new BeansWrapperBuilder(Configuration.VERSION_2_3_19).build());
} finally {
Thread.currentThread().setContextClassLoader(oldTCCL);
}
assertSame(bw1, new BeansWrapperBuilder(Configuration.VERSION_2_3_19).build());
assertEquals(2, getBeansWrapperInstanceCacheSize());
BeansWrapper bw3;
Thread.currentThread().setContextClassLoader(newTCCL);
try {
assertSame(bw2, new BeansWrapperBuilder(Configuration.VERSION_2_3_19).build());
bw3 = new BeansWrapperBuilder(Configuration.VERSION_2_3_21).build();
assertEquals(3, getBeansWrapperInstanceCacheSize());
hardReferences.add(bw3);
} finally {
Thread.currentThread().setContextClassLoader(oldTCCL);
}
BeansWrapper bw4 = new BeansWrapperBuilder(Configuration.VERSION_2_3_21).build();
assertEquals(4, getBeansWrapperInstanceCacheSize());
hardReferences.add(bw4);
assertNotSame(bw3, bw4);
assertTrue(hardReferences.size() != 0); // just to save it from GC until this line
}
public void testClassInrospectorCache() throws TemplateModelException {
assertFalse(new BeansWrapper().isClassIntrospectionCacheRestricted());
assertFalse(new BeansWrapper(Configuration.VERSION_2_3_21).isClassIntrospectionCacheRestricted());
assertTrue(new BeansWrapperBuilder(Configuration.VERSION_2_3_20).build().isClassIntrospectionCacheRestricted());
ClassIntrospectorBuilder.clearInstanceCache();
BeansWrapperBuilder.clearInstanceCache();
checkClassIntrospectorCacheSize(0);
List<BeansWrapper> hardReferences = new LinkedList<BeansWrapper>();
BeansWrapperBuilder factory;
{
factory = new BeansWrapperBuilder(Configuration.VERSION_2_3_19);
BeansWrapper bw1 = factory.build();
checkClassIntrospectorCacheSize(1);
factory.setExposureLevel(BeansWrapper.EXPOSE_SAFE); // this was already set to this
factory.setSimpleMapWrapper(true); // this shouldn't matter for the introspection cache
BeansWrapper bw2 = factory.build();
checkClassIntrospectorCacheSize(1);
assertSame(bw2.getClassIntrospector(), bw1.getClassIntrospector());
assertNotSame(bw1, bw2);
// Wrapping tests:
assertFalse(exposesFields(bw1));
assertTrue(exposesProperties(bw1));
assertTrue(exposesMethods(bw1));
assertFalse(exposesUnsafe(bw1));
assertFalse(isSimpleMapWrapper(bw1));
assertTrue(bw1.isClassIntrospectionCacheRestricted());
// Prevent introspection cache GC:
hardReferences.add(bw1);
hardReferences.add(bw2);
}
{
factory = new BeansWrapperBuilder(Configuration.VERSION_2_3_19);
factory.setExposeFields(true);
BeansWrapper bw = factory.build();
checkClassIntrospectorCacheSize(2);
// Wrapping tests:
assertTrue(exposesFields(bw));
assertTrue(exposesProperties(bw));
assertTrue(exposesMethods(bw));
assertFalse(exposesUnsafe(bw));
assertFalse(isSimpleMapWrapper(bw));
// Prevent introspection cache GC:
hardReferences.add(bw);
}
{
factory.setExposureLevel(BeansWrapper.EXPOSE_ALL);
BeansWrapper bw = factory.build();
checkClassIntrospectorCacheSize(3);
// Wrapping tests:
assertTrue(exposesFields(bw));
assertTrue(exposesProperties(bw));
assertTrue(exposesMethods(bw));
assertTrue(exposesUnsafe(bw));
assertFalse(isSimpleMapWrapper(bw));
// Prevent introspection cache GC:
hardReferences.add(bw);
}
{
factory.setExposeFields(false);
BeansWrapper bw = factory.build();
checkClassIntrospectorCacheSize(4);
// Wrapping tests:
assertFalse(exposesFields(bw));
assertTrue(exposesProperties(bw));
assertTrue(exposesMethods(bw));
assertTrue(exposesUnsafe(bw));
assertFalse(isSimpleMapWrapper(bw));
// Prevent introspection cache GC:
hardReferences.add(bw);
}
{
factory.setExposureLevel(BeansWrapper.EXPOSE_NOTHING);
BeansWrapper bw = factory.build();
checkClassIntrospectorCacheSize(5);
// Wrapping tests:
assertFalse(exposesFields(bw));
assertFalse(exposesProperties(bw));
assertFalse(exposesMethods(bw));
assertFalse(exposesUnsafe(bw));
assertFalse(isSimpleMapWrapper(bw));
// Prevent introspection cache GC:
hardReferences.add(bw);
}
{
factory.setExposeFields(true);
BeansWrapper bw = factory.build();
checkClassIntrospectorCacheSize(6);
// Wrapping tests:
assertTrue(exposesFields(bw));
assertFalse(exposesProperties(bw));
assertFalse(exposesMethods(bw));
assertFalse(exposesUnsafe(bw));
assertFalse(isSimpleMapWrapper(bw));
// Prevent introspection cache GC:
hardReferences.add(bw);
}
{
factory.setExposureLevel(BeansWrapper.EXPOSE_PROPERTIES_ONLY);
BeansWrapper bw = factory.build();
checkClassIntrospectorCacheSize(7);
// Wrapping tests:
assertTrue(exposesFields(bw));
assertTrue(exposesProperties(bw));
assertFalse(exposesMethods(bw));
assertFalse(exposesUnsafe(bw));
assertFalse(isSimpleMapWrapper(bw));
// Prevent introspection cache GC:
hardReferences.add(bw);
}
{
factory = new BeansWrapperBuilder(Configuration.VERSION_2_3_21);
factory.setExposeFields(false);
factory.setExposureLevel(BeansWrapper.EXPOSE_PROPERTIES_ONLY);
BeansWrapper bw1 = factory.build();
checkClassIntrospectorCacheSize(8);
ClassIntrospector ci1 = bw1.getClassIntrospector();
factory.setSimpleMapWrapper(true); // Shouldn't mater
BeansWrapper bw2 = factory.build();
ClassIntrospector ci2 = bw2.getClassIntrospector();
checkClassIntrospectorCacheSize(8);
assertSame(ci1, ci2);
assertNotSame(bw1, bw2);
// Wrapping tests:
assertFalse(exposesFields(bw1));
assertTrue(exposesProperties(bw1));
assertFalse(exposesMethods(bw1));
assertFalse(exposesUnsafe(bw1));
assertFalse(isSimpleMapWrapper(bw1));
// Prevent introspection cache GC:
hardReferences.add(bw1);
hardReferences.add(bw2);
}
BeansWrapperBuilder.clearInstanceCache(); // otherwise ClassInrospector cache couldn't become cleared in reality
_TemplateAPI.DefaultObjectWrapperFactory_clearInstanceCache();
clearClassIntrospectorInstanceCacheReferences(false);
checkClassIntrospectorCacheSize(8);
assertEquals(0, getClassIntrospectorNonClearedInstanceCacheSize());
{
factory.setSimpleMapWrapper(false);
factory.setExposeFields(false);
BeansWrapper bw1 = factory.build();
checkClassIntrospectorCacheSize(8);
assertEquals(1, getClassIntrospectorNonClearedInstanceCacheSize());
ClassIntrospector ci1 = bw1.getClassIntrospector();
factory.setSimpleMapWrapper(true); // Shouldn't mater
BeansWrapper bw2 = factory.build();
ClassIntrospector ci2 = bw2.getClassIntrospector();
assertSame(ci1, ci2);
assertNotSame(bw1, bw2);
// Wrapping tests:
assertFalse(exposesFields(bw1));
assertTrue(exposesProperties(bw1));
assertFalse(exposesMethods(bw1));
assertFalse(exposesUnsafe(bw1));
assertFalse(isSimpleMapWrapper(bw1));
// Prevent introspection cache GC:
hardReferences.add(bw1);
hardReferences.add(bw2);
}
{
factory = new BeansWrapperBuilder(Configuration.VERSION_2_3_19);
BeansWrapper bw = factory.build();
checkClassIntrospectorCacheSize(8);
assertEquals(2, getClassIntrospectorNonClearedInstanceCacheSize());
// Wrapping tests:
assertFalse(exposesFields(bw));
assertTrue(exposesProperties(bw));
assertTrue(exposesMethods(bw));
assertFalse(exposesUnsafe(bw));
// Prevent introspection cache GC:
hardReferences.add(bw);
}
clearClassIntrospectorInstanceCacheReferences(true);
checkClassIntrospectorCacheSize(8);
assertEquals(0, getClassIntrospectorNonClearedInstanceCacheSize());
{
factory = new BeansWrapperBuilder(Configuration.VERSION_2_3_21);
factory.setExposeFields(true);
BeansWrapper bw = factory.build();
checkClassIntrospectorCacheSize(1);
// Wrapping tests:
assertTrue(exposesFields(bw));
assertTrue(exposesProperties(bw));
assertTrue(exposesMethods(bw));
assertFalse(exposesUnsafe(bw));
// Prevent introspection cache GC:
hardReferences.add(bw);
}
{
factory = new BeansWrapperBuilder(Configuration.VERSION_2_3_19);
factory.setMethodAppearanceFineTuner(new MethodAppearanceFineTuner() {
public void process(MethodAppearanceDecisionInput in, MethodAppearanceDecision out) {
}
}); // spoils ClassIntrospector() sharing
BeansWrapper bw1 = factory.build();
assertSame(bw1, factory.build());
factory.setSimpleMapWrapper(true);
BeansWrapper bw2 = factory.build();
checkClassIntrospectorCacheSize(1);
assertNotSame(bw1, bw2);
assertNotSame(bw1.getClassIntrospector(), bw2.getClassIntrospector());
assertTrue(bw1.isClassIntrospectionCacheRestricted());
assertTrue(bw2.isClassIntrospectionCacheRestricted());
// Wrapping tests:
assertFalse(exposesFields(bw1));
assertFalse(exposesFields(bw2));
assertTrue(exposesProperties(bw1));
assertTrue(exposesProperties(bw2));
assertTrue(exposesMethods(bw1));
assertTrue(exposesMethods(bw2));
assertFalse(exposesUnsafe(bw1));
assertFalse(exposesUnsafe(bw2));
assertFalse(isSimpleMapWrapper(bw1));
assertTrue(isSimpleMapWrapper(bw2));
}
{
factory = new BeansWrapperBuilder(Configuration.VERSION_2_3_19);
factory.setMethodAppearanceFineTuner(GetlessMethodsAsPropertyGettersRule.INSTANCE); // doesn't spoils sharing
BeansWrapper bw1 = factory.build();
assertSame(bw1, factory.build());
checkClassIntrospectorCacheSize(2);
factory.setSimpleMapWrapper(true);
BeansWrapper bw2 = factory.build();
checkClassIntrospectorCacheSize(2);
assertNotSame(bw1, bw2);
assertSame(bw1.getClassIntrospector(), bw2.getClassIntrospector()); // !
assertTrue(bw1.isClassIntrospectionCacheRestricted());
assertTrue(bw2.isClassIntrospectionCacheRestricted());
// Wrapping tests:
assertFalse(exposesFields(bw1));
assertFalse(exposesFields(bw2));
assertTrue(exposesProperties(bw1));
assertTrue(exposesProperties(bw2));
assertTrue(exposesMethods(bw1));
assertTrue(exposesMethods(bw2));
assertFalse(exposesUnsafe(bw1));
assertFalse(exposesUnsafe(bw2));
assertFalse(isSimpleMapWrapper(bw1));
assertTrue(isSimpleMapWrapper(bw2));
}
assertTrue(hardReferences.size() != 0); // just to save it from GC until this line
}
private void checkClassIntrospectorCacheSize(int expectedSize) {
assertEquals(expectedSize, getClassIntrospectorInstanceCacheSize());
}
private void assertNotEquals(Object o1, Object o2) {
assertFalse(o1.equals(o2));
}
public class C {
public String foo = "FOO";
public String getBar() {
return "BAR";
}
}
private boolean isSimpleMapWrapper(BeansWrapper bw) throws TemplateModelException {
return bw.wrap(new HashMap()) instanceof SimpleMapModel;
}
private boolean exposesFields(BeansWrapper bw) throws TemplateModelException {
TemplateHashModel thm = (TemplateHashModel) bw.wrap(new C());
TemplateScalarModel r = (TemplateScalarModel) thm.get("foo");
if (r == null) return false;
assertEquals("FOO", r.getAsString());
return true;
}
private boolean exposesProperties(BeansWrapper bw) throws TemplateModelException {
TemplateHashModel thm = (TemplateHashModel) bw.wrap(new C());
TemplateScalarModel r = (TemplateScalarModel) thm.get("bar");
if (r == null) return false;
assertEquals("BAR", r.getAsString());
return true;
}
private boolean exposesMethods(BeansWrapper bw) throws TemplateModelException {
TemplateHashModel thm = (TemplateHashModel) bw.wrap(new C());
return thm.get("getBar") != null;
}
private boolean exposesUnsafe(BeansWrapper bw) throws TemplateModelException {
TemplateHashModel thm = (TemplateHashModel) bw.wrap(new C());
return thm.get("wait") != null;
}
static int getClassIntrospectorInstanceCacheSize() {
Map instanceCache = ClassIntrospectorBuilder.getInstanceCache();
synchronized (instanceCache) {
return instanceCache.size();
}
}
static int getClassIntrospectorNonClearedInstanceCacheSize() {
Map instanceCache = ClassIntrospectorBuilder.getInstanceCache();
synchronized (instanceCache) {
int cnt = 0;
for (Iterator it = instanceCache.values().iterator(); it.hasNext(); ) {
if (((Reference) it.next()).get() != null) cnt++;
}
return cnt;
}
}
static void clearClassIntrospectorInstanceCacheReferences(boolean enqueue) {
Map instanceCache = ClassIntrospectorBuilder.getInstanceCache();
synchronized (instanceCache) {
for (Iterator it = instanceCache.values().iterator(); it.hasNext(); ) {
Reference ref = ((Reference) it.next());
ref.clear();
if (enqueue) {
ref.enqueue();
}
}
}
}
static int getBeansWrapperInstanceCacheSize() {
Map instanceCache = BeansWrapperBuilder.getInstanceCache();
synchronized (instanceCache) {
int size = 0;
for (Iterator it1 = instanceCache.values().iterator(); it1.hasNext(); ) {
size += ((Map) it1.next()).size();
}
return size;
}
}
static int getBeansWrapperNonClearedInstanceCacheSize() {
Map instanceCache = BeansWrapperBuilder.getInstanceCache();
synchronized (instanceCache) {
int cnt = 0;
for (Iterator it1 = instanceCache.values().iterator(); it1.hasNext(); ) {
Map tcclScope = (Map) it1.next();
for (Iterator it2 = tcclScope.values().iterator(); it2.hasNext(); ) {
if (((Reference) it2.next()).get() != null) cnt++;
}
}
return cnt;
}
}
static void clearBeansWrapperInstanceCacheReferences(boolean enqueue) {
Map instanceCache = BeansWrapperBuilder.getInstanceCache();
synchronized (instanceCache) {
for (Iterator it1 = instanceCache.values().iterator(); it1.hasNext(); ) {
Map tcclScope = (Map) it1.next();
for (Iterator it2 = tcclScope.values().iterator(); it2.hasNext(); ) {
Reference ref = ((Reference) it2.next());
ref.clear();
if (enqueue) {
ref.enqueue();
}
}
}
}
}
}