Tipo de seguridad: Fundido sin control


En mi archivo de contexto de la aplicación de spring, tengo algo como:

<util:map id="someMap" map-class="java.util.HashMap" key-type="java.lang.String" value-type="java.lang.String">
    <entry key="some_key" value="some value" />
    <entry key="some_key_2" value="some value" />   
</util:map>

En la clase java, la implementación se ve como:

private Map<String, String> someMap = new HashMap<String, String>();
someMap = (HashMap<String, String>)getApplicationContext().getBean("someMap");

En Eclipse, veo una advertencia que dice:

Seguridad de tipo: Fundido sin marcar del objeto al HashMap

¿Qué hice mal? ¿Cómo resuelvo el problema?

Author: FabienB, 2008-11-04

9 answers

Bueno, en primer lugar, estás desperdiciando memoria con la nueva llamada de creación HashMap. Su segunda línea ignora completamente la referencia a este hashmap creado, haciéndolo disponible para el recolector de basura. Así que, no hagas eso, usa:

private Map<String, String> someMap = (HashMap<String, String>)getApplicationContext().getBean("someMap");

En Segundo lugar, el compilador se queja de que convertir el objeto a un HashMap sin comprobar si es un HashMap. Pero, incluso si tuvieras que hacer:

if(getApplicationContext().getBean("someMap") instanceof HashMap) {
    private Map<String, String> someMap = (HashMap<String, String>)getApplicationContext().getBean("someMap");
}

Probablemente todavía recibirías esta advertencia. El problema es, getBean devuelve Object, así se desconoce cuál es el tipo. Convertirlo a HashMap directamente no causaría el problema con el segundo caso (y quizás no habría una advertencia en el primer caso, no estoy seguro de cuán pedante es el compilador de Java con las advertencias para Java 5). Sin embargo, lo estás convirtiendo a HashMap<String, String>.

Los HashMaps son realmente mapas que toman un objeto como clave y tienen un objeto como valor, HashMap<Object, Object> si se quiere. Por lo tanto, no hay garantía de que cuando usted consigue su frijol que puede ser representado como un HashMap<String, String> porque podría tener HashMap<Date, Calendar> porque la representación no genérica que se devuelve puede tener cualquier objeto.

Si el código se compila, y puede ejecutar String value = map.get("thisString"); sin ningún error, no se preocupe por esta advertencia. Pero si el mapa no es completamente de claves de cadena a valores de cadena, obtendrá un ClassCastException en tiempo de ejecución, porque los genéricos no pueden bloquear que esto suceda en este caso.

 218
Author: MetroidFan2002,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-02-07 12:55:44

El problema es que un cast es una comprobación en tiempo de ejecución, pero debido a la eliminación de tipos, en tiempo de ejecución no hay diferencia entre un HashMap<String,String> y HashMap<Foo,Bar> para cualquier otro Foo y Bar.

Use @SuppressWarnings("unchecked") y sujete la nariz. Oh, y campaña para genéricos reificados en Java:)

 264
Author: Jon Skeet,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-11-04 17:09:19

Como indican los mensajes anteriores, la Lista no puede diferenciarse entre a List<Object> y a List<String> o List<Integer>.

He resuelto este mensaje de error para un problema similar:

List<String> strList = (List<String>) someFunction();
String s = strList.get(0);

Con lo siguiente:

List<?> strList = (List<?>) someFunction();
String s = (String) strList.get(0);

Explicación: La primera conversión de tipos verifica que el objeto es una Lista sin importar los tipos mantenidos dentro (ya que no podemos verificar los tipos internos a nivel de Lista). La segunda conversión ahora es necesaria porque el compilador solo conoce la Lista contiene algún tipo de objetos. Esto verifica el tipo de cada objeto de la Lista a medida que se accede a él.

 60
Author: Larry Landry,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-08-02 10:05:02

Una advertencia es solo eso. Advertencia. A veces las advertencias son irrelevantes, a veces no lo son. Se utilizan para llamar su atención sobre algo que el compilador piensa que podría ser un problema, pero puede que no lo sea.

En el caso de los moldes, siempre va a dar una advertencia en este caso. Si está absolutamente seguro de que un cast en particular será seguro, entonces debería considerar agregar una anotación como esta (no estoy seguro de la sintaxis) justo antes de la línea:

@SuppressWarnings (value="unchecked")
 21
Author: David M. Karr,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-11-04 16:44:24

Está recibiendo este mensaje porque getBean devuelve una referencia de objeto y lo está enviando al tipo correcto. Java 1.5 le da una advertencia. Esa es la naturaleza de usar Java 1.5 o mejor con código que funciona así. Spring tiene la versión typesafe

someMap=getApplicationContext().getBean<HashMap<String, String>>("someMap");

En su lista de tareas pendientes.

 9
Author: David Nehme,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-11-04 16:44:59

Si realmente desea deshacerse de las advertencias, una cosa que puede hacer es crear una clase que se extienda desde la clase genérica.

Por ejemplo, si está tratando de usar

private Map<String, String> someMap = new HashMap<String, String>();

Puede crear una nueva clase como tal

public class StringMap extends HashMap<String, String>()
{
    // Override constructors
}

Luego, cuando use

someMap = (StringMap) getApplicationContext().getBean("someMap");

El compilador SABE cuáles son los tipos (ya no genéricos), y no habrá advertencia. Esto puede no ser siempre la solución perfecta, algunos podrían argumentar que este tipo de derrotas el propósito de las clases genéricas, pero todavía estás reutilizando todo el mismo código de la clase genérica, solo estás declarando en tiempo de compilación qué tipo quieres usar.

 5
Author: Rabbit,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-04-13 15:55:31

Otra solución, si te encuentras lanzando el mismo objeto mucho y no quieres ensuciar tu código con @SupressWarnings("unchecked"), sería crear un método con la anotación. De esta manera estás centralizando el reparto y, con suerte, reduciendo la posibilidad de error.

@SuppressWarnings("unchecked")
public static List<String> getFooStrings(Map<String, List<String>> ctx) {
    return (List<String>) ctx.get("foos");
}
 1
Author: Jeremy,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-10-20 19:25:17

El siguiente código causa el Tipo Advertencia de seguridad

Map<String, Object> myInput = (Map<String, Object>) myRequest.get();

Solución alternativa

Cree un nuevo objeto Map sin mencionar los parámetros porque el tipo de objeto contenido en la lista no está verificado.

Paso 1: Crear un nuevo mapa temporal

Map<?, ?> tempMap = (Map<?, ?>) myRequest.get();

Paso 2: Instanciar el mapa principal

Map<String, Object> myInput=new HashMap<>(myInputObj.size());

Paso 3: Iterar el mapa temporal y establecer los valores en el Mapa principal

 for(Map.Entry<?, ?> entry :myInputObj.entrySet()){
        myInput.put((String)entry.getKey(),entry.getValue()); 
    }
 0
Author: Andy,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-12-16 14:23:25

La solución para evitar la advertencia sin marcar:

class MyMap extends HashMap<String, String> {};
someMap = (MyMap)getApplicationContext().getBean("someMap");
 0
Author: ochakov,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-08-28 15:50:10