DEV Community

Nancy Deschenes
Nancy Deschenes

Posted on

7 3

Today, I learned that Tuple != Tuple2

Once upon a time, I wrote a service class that generates pairs of users. I thought to myself, "Ohh! I know this! I need to return a list of tuples!"

List<Tuple<User, User>> getUserMatches() {
  List<Tuple<User, User>> returnVal = []
  while (moreUsers()) {
    User a = getUserA()
    User b = getUserB() 
    returnVal.add(new Tuple[a, b])
  }
}
Enter fullscreen mode Exit fullscreen mode

Test the code. The code runs. All is good. Move on.

Later, a co-worker asks, "why aren't the tests running?" What? no, my tests run, I'm sure! On closer inspection, not only do the tests not pass, they fail to compile. I shake my head. I can't imagine... What's worse, IntelliJ shows absolutely no compilation problems. Without a compilation error, it's hard to fix the problem. What I get instead is an exception:

java.lang.reflect.MalformedParameterizedTypeException
    at sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl.validateConstructorArguments(ParameterizedTypeImpl.java:60)
    at sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl.<init>(ParameterizedTypeImpl.java:53)
    at sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl.make(ParameterizedTypeImpl.java:95)
    at sun.reflect.generics.factory.CoreReflectionFactory.makeParameterizedType(CoreReflectionFactory.java:105)
    at sun.reflect.generics.visitor.Reifier.visitClassTypeSignature(Reifier.java:140)
[...]
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:606)
    at org.codehaus.groovy.grails.cli.support.GrailsStarter.rootLoader(GrailsStarter.java:236)
    at org.codehaus.groovy.grails.cli.support.GrailsStarter.main(GrailsStarter.java:264)

Enter fullscreen mode Exit fullscreen mode

Some googling leads me this blog post. Ah, okay, I need to find out where I managed to parametrize a class incorrectly.

The exception only occurs when compiling the tests, so that where I look. I try to get the system to only compile some of the tests, to figure out which is causing the problem. Finally find that the test for my service above is responsible. I still have no idea what's wrong with it, mind you. All I know is that when I try to compile it, it fails with the dreaded java.lang.reflect.MalformedParameterizedTypeException.

I comment out half the file. The problem still happens. I comment out another quarter. Another eighth. Until all I have left is

@TestFor(UserMergeService) 
class UserMergeServiceSpec extends Specification {
}
Enter fullscreen mode Exit fullscreen mode

And it still crashes the compiler. I comment out the annotation, and it compiles! I put the whole file back in, and as long as the annotation is commented out, it works.

It was positively mystifying.

I tried to approach it from the other end. I set a breakpoint where the MalformedParameterizedTypeException was thrown, and walked up the stack, and looked at local values, and... there's my Tuple. I look at the definition:

public class Tuple extends AbstractList {
  // ...
}
Enter fullscreen mode Exit fullscreen mode

Hm. That's not parametrized. How do you parametrize a Tuple, then?

That's when I found this blog post that cleared everything up.

Tuple is an immutable list of items, and is not parametrizable. Tuple2 is a pair of two things, and the class of those two things can be parametrized.

I don't know why this was a problem only when running the tests; the code compiles and runs just fine on its own, and the "bad code" is in the Service class, not in the test, but the test must have tickled something... At least it's fixed!

Image of Timescale

🚀 pgai Vectorizer: SQLAlchemy and LiteLLM Make Vector Search Simple

We built pgai Vectorizer to simplify embedding management for AI applications—without needing a separate database or complex infrastructure. Since launch, developers have created over 3,000 vectorizers on Timescale Cloud, with many more self-hosted.

Read more

Top comments (1)

Collapse
 
david_ojeda profile image
David Ojeda •

Nice post, thanks!

Glad to see some Grails, Groovy and Spock around here 🖖🏼

Sentry image

See why 4M developers consider Sentry, “not bad.”

Fixing code doesn’t have to be the worst part of your day. Learn how Sentry can help.

Learn more

đź‘‹ Kindness is contagious

Explore a sea of insights with this enlightening post, highly esteemed within the nurturing DEV Community. Coders of all stripes are invited to participate and contribute to our shared knowledge.

Expressing gratitude with a simple "thank you" can make a big impact. Leave your thanks in the comments!

On DEV, exchanging ideas smooths our way and strengthens our community bonds. Found this useful? A quick note of thanks to the author can mean a lot.

Okay