There seem to be a significant amount of Java developers who have certain criticisms to the Java approach of implementing Generics. Though type information is sometimes well hidden, it's almost always available. This is because of the approach that Sun took when defining it. Sun decided that it was not appropriate to compile new types just because the type information itself changed. This approach differs from the C++ template approach which requires the original sources of the generic class you're using, this makes it very hard to provide a generic class in a library.

Then there is the subtle matter of type erasure. The problem here lies in that in the following case, the type information is not sufficient to differentiate the complete generic types:

private List<String> stringList = new LinkedList<String>();
@Test
public void testErasure() {
	List<Integer> integerList = new LinkedList<Integer>();
	Assert.assertEquals(integerList.getClass(),
		stringList.getClass());
}
This test completes successfully. Also, we can do 'nasty' things like this:
@Test
public void testErasureCast() {
	@SuppressWarnings("rawtypes")
	List rawList = stringList;
	@SuppressWarnings("unchecked")
	List<Integer> integerList = rawList;
	Assert.assertNotNull(integerList);
}
Although, instead of complaining that the language is not typed strong enough, I consider this to be a classic case of 'pebkac', or 'problem exists between keyboard and chair', or 'failure to program'. The fact that the Java allows these constructs is most of a developer problem than a language problem. To illustrate, nobody should do this:
@Test
public void testBadCasting() {
	String someString = "";
	Object someObject = someString;
	try {
		Integer someInteger = (Integer) someObject;
		Assert.assertNotNull(someInteger);
		Assert.fail("No compiler should accept this!");
	} catch (ClassCastException e) {
		// Very obvious!
	}
}
Nobody should do this either:
@Test
public void testWorseCasting() {
	String someString = null;
	Object someObject = someString;
	Integer someInteger = (Integer) someObject;
	Assert.assertNull(someInteger);
}

When looking up types through reflection, it's not hard to see that finding whatever you're looking for, can be quite a task. Having played with reflection, the most useful class you're going to find is the ParameterizedType. When looking through a classes type hierarchy, which in itself can be very complex, it will hold all relevant type information, like the TypeVariable one might be trying to resole or the concrete Class it might resolve to. Such as in the case of the first code snippet:

private List<String> stringList = new LinkedList<String>();
@Test
public void testParameterizedType() {
	try {
		Field stringListField = GenericsTest.class.
				getDeclaredField("stringList");
		Assert.assertTrue(stringListField.getGenericType()
     			instanceof ParameterizedType);
		ParameterizedType stringListGenericType = (ParameterizedType)
     			stringListField.getGenericType();
		Assert.assertEquals(List.class, stringListGenericType.
				getRawType());
		Assert.assertEquals(1, stringListGenericType.
				getActualTypeArguments().length);
		Assert.assertEquals(String.class, stringListGenericType.
				getActualTypeArguments()[0]);
	} catch (SecurityException e) {
		Assert.fail(e.getMessage());
	} catch (NoSuchFieldException e) {
		Assert.fail(e.getMessage());
	}
}
The complete example can be found here.

Having worked with the Generics implementation of Java. One can easily argue that it's just a hack on the language itself or just partially complete. I disagree with those statements, the changes they made do not just allow backwards compatibility to the language, they provide a complete implementation of what was to be achieved. Additionally when programming properly, they provide a correct and complete way to use generics. Also, Sun has successfully modified the reflection API to properly reflect the changes they implemented. Personally I believe that there is no optimal way to implement generics, the Java way happens to appeal to my vision on implementing it. But what I do hope, is that Oracle finds a neat and proper way to either extend the Object class to include a method such as 'getGenericType' or something with less impact, finding a way to enhance the Class class to include information specific to a given instance. We do have to consider that there is hardly any reasonably way to implement this in a backwards compatible way.