/* * Copyright 2016 higherfrequencytrading.com * * 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 net.openhft.lang.io.serialization.impl; import net.openhft.lang.Compare; import net.openhft.lang.io.Bytes; import net.openhft.lang.io.serialization.CompactBytesMarshaller; import net.openhft.lang.model.constraints.NotNull; import net.openhft.lang.model.constraints.Nullable; import net.openhft.lang.pool.StringInterner; import java.lang.ref.WeakReference; import java.math.BigDecimal; import java.math.BigInteger; import java.util.Date; import java.util.LinkedHashMap; import java.util.Map; /** * @author peter.lawrey */ public class ClassMarshaller extends ImmutableMarshaller<Class> implements CompactBytesMarshaller<Class> { private static final int CACHE_SIZE = 1019; private static final Map<String, Class> SC_SHORT_NAME = new LinkedHashMap<String, Class>(); private static final Map<Class, String> CS_SHORT_NAME = new LinkedHashMap<Class, String>(); private static final StringBuilderPool sbp = new StringBuilderPool(); static { Class[] classes = {Boolean.class, Byte.class, Character.class, Short.class, Integer.class, Long.class, Float.class, Double.class, String.class, Class.class, BigInteger.class, BigDecimal.class, Date.class}; for (Class clazz : classes) { String simpleName = clazz.getSimpleName(); SC_SHORT_NAME.put(simpleName, clazz); CS_SHORT_NAME.put(clazz, simpleName); } } private final ClassLoader classLoader; @Nullable @SuppressWarnings("unchecked") private WeakReference<Class>[] classWeakReference = null; public ClassMarshaller(ClassLoader classLoader) { this.classLoader = classLoader; } @Override public void write(@NotNull Bytes bytes, @NotNull Class aClass) { String s = CS_SHORT_NAME.get(aClass); if (s == null) s = aClass.getName(); bytes.writeUTFΔ(s); } @Nullable @Override public Class read(@NotNull Bytes bytes) { StringBuilder sb = sbp.acquireStringBuilder(); bytes.readUTFΔ(sb); return load(sb); } @Nullable private Class load(@NotNull CharSequence name) { int hash = (int) (Compare.calcLongHashCode(name) & 0x7ffffff) % CACHE_SIZE; if (classWeakReference == null) //noinspection unchecked classWeakReference = new WeakReference[CACHE_SIZE]; WeakReference<Class> ref = classWeakReference[hash]; if (ref != null) { Class clazz = ref.get(); if (clazz != null && StringInterner.isEqual(clazz.getName(), name)) return clazz; } try { String className = name.toString(); Class<?> clazz = SC_SHORT_NAME.get(className); if (clazz != null) return clazz; clazz = classLoader.loadClass(className); classWeakReference[hash] = new WeakReference<Class>(clazz); return clazz; } catch (ClassNotFoundException e) { throw new IllegalArgumentException(e); } } @Override public byte code() { return CLASS_CODE; // control C } }