All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.google.gwt.user.server.rpc.EnumMapUtil Maven / Gradle / Ivy

There is a newer version: 2.12.1
Show newest version
/*
 * Copyright 2022 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.gwt.user.server.rpc;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.ObjectStreamClass;

/**
 * A utility to extract the key type of any {@link java.util.EnumMap}, even if it is empty. Some
 * frameworks have tried this by using reflection on the map's private field {@code keyType}, but
 * that approach breaks with Java 17 where reflection on private elements of any {@code java.*}
 * class is forbidden unless the {@code --add-opens} VM argument is used which is a fairly unsafe
 * thing to do.
 * 

* * Use like this:

 *      private static enum MyBoolean {
 *          TRUE, FALSE
 *      };
 *      EnumMap enumMap = new EnumMap<>(MyBoolean.class);
 *      Class c = EnumMapUtil.getKeyType(enumMap);
 * 
*

* * Implementation note: If the map passed to {@link #getKeyType(java.util.EnumMap)} is not empty, * the first key is obtained from the {@link EnumMap#keySet() key set} and its type is determined * and returned. If the map is empty, it is serialized into an {@link ObjectOutputStream} writing to * a {@link ByteArrayOutputStream} from which it is read again with a specialized * {@link ObjectInputStream}where the {@code resolveClass} method is overridden. Upon reading a * class descriptor for class {@link java.util.EnumMap}, instead of regularly resolving the class * descriptor a package-protected class {@link com.google.gwt.user.server.rpc.EnumMap} is returned * which has a serial version UID equal to that of {@link java.util.EnumMap} and the same set of * fields. By having the same simple name (despite living in a different package) the * {@link ObjectInputStream} considers this class to be compatible to {@link java.util.EnumMap} and * de-serializes the stream contents into an instance of * {@link com.google.gwt.user.server.rpc.EnumMap} which in turn offers a public getter * {@link com.google.gwt.user.server.rpc.EnumMap#getKeyType()} for the key type. Through this getter * the key type is then determined and returned. * */ public class EnumMapUtil { private static class MyObjectInputStream extends ObjectInputStream { public MyObjectInputStream(InputStream in) throws IOException { super(in); } @Override protected Class resolveClass(ObjectStreamClass desc) throws IOException, ClassNotFoundException { Class result = null; if (desc.getName().equals("java.util.EnumMap")) { result = EnumMap.class; } else { try { result = super.resolveClass(desc); } catch (ClassNotFoundException e) { result = Class.forName(desc.getName(), false, Thread.currentThread() .getContextClassLoader()); } } return result; } } public static , V> Class getKeyType(java.util.EnumMap enumMap) throws IOException, ClassNotFoundException { final Class result; if (enumMap.isEmpty()) { final ByteArrayOutputStream bos = new ByteArrayOutputStream(); final ObjectOutputStream oos = new ObjectOutputStream(bos); oos.writeObject(enumMap); oos.close(); final ObjectInputStream ois = new MyObjectInputStream(new ByteArrayInputStream(bos .toByteArray())); @SuppressWarnings("unchecked") final EnumMap readMap = (EnumMap) ois.readObject(); final Class keyType = readMap.getKeyType(); result = keyType; } else { result = enumMap.keySet().iterator().next().getDeclaringClass(); } return result; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy