2012-11-13 18 views
16

Biorąc klasy Java z dwóch metod (zaczerpnięte z Mockito):Siła pojedynczy argument Scala varargs

OngoingStubbing<T> thenReturn(T value); 

OngoingStubbing<T> thenReturn(T value, T... values); 

Gdybym powoływać od Scala z

....thenReturn("something") 

dostaję błąd:

Description Resource Path Location Type 
ambiguous reference to overloaded definition, both method thenReturn in trait OngoingStubbing of type (x$1: java.lang.Object, x$2: <repeated...>[java.lang.Object])org.mockito.stubbing.OngoingStubbing[java.lang.Object] and method thenReturn in trait OngoingStubbing of type (x$1: java.lang.Object)org.mockito.stubbing.OngoingStubbing[java.lang.Object] match argument types (java.lang.String) 

I nie mogę wymyślić, jak to naprawić.

Odpowiedz

12

Odpowiedzi na te pytania są niewłaściwe. Różnica jest subtelna, ale nie jest to ten sam problem, co w przypadku linked ticket. To wymaga nieuzasadnionej gimnastyki, aby wywołać metodę non-varargs. Do tego wystarczy:

thenReturn[String]("something") 

Albo, jeśli nie chcesz tego zrobić z jakiegoś powodu, nie potrzebujesz aliasu typu i obsady. Możesz bezpośrednio użyć typu strukturalnego.

(this: { def thenReturn[T](s: T): OngoingStubbing[T] }).thenReturn("something") 

Chodzi tu wpisać wnioskowanie na skrzyżowaniu przeciążenia i polimorfizmu - jedna metoda jest bardziej szczegółowy, ale scalac nie zorientować się, które. Kwestia w SI-2991 jest prawdziwą niejednoznacznością ze względu na interakcję między przeciążaniem i konwersją krotek - nie jest też bardziej konkretna.

+1

Problem polega na tym, że kiedy uporczywie stosujesz metodę zwracającą java.lang.Object (aka AnyRef), a następnie jesteś spieprzony przez Scalę. –

+0

Myślę, że masz na myśli AnyVal, który nie jest obiektem –

1

Rozwiązaniem jest dość proste:

OngoingStubbing<T> thenReturn(T value); 

OngoingStubbing<T> thenReturn(T value1, T valu2, T... values); 

nie ma "varargs musi być non pusty" funkcji.

+0

Nie mogę zmienić podstawowej biblioteki. Przykładowe metody są pobierane z mockito. – monkjack

+0

Yo można zawinąć w podstawową bibliotekę lub zawsze wywoływać drugą metodę. Jak wyjaśnił Alexey w drugiej odpowiedzi. – Nicolas

9

Jeśli wywołanie wersji vararg jest dopuszczalne,

thenReturn("something", Nil: _*) 

Nie można myśleć o sposób do wywołania metody bez varargs teraz.

+0

to działa dla mnie w moim przypadku doReturn (false, Nil: _ *) pozwala mi ominąć wymagania AnyRef z drugiego elipsis param –

16

Jest to znany problem interoperacyjności Scala-Java, choć niestety nie ma go w FAQ. Oto Scala ticket describing the problem. Zasadniczo obie metody mają zastosowanie, gdy podajesz pojedynczy argument, a kompilator Scala nie ma obecnie żadnej heurystyki, aby zdecydować, który z nich jest "bardziej szczegółowy". Alexey Romanov's approach to always use the varargs version jest dobrym obejście:

thenReturn("something", Nil: _*) 

Istnieje również question running into a similar problem with JCommander. Jedna z odpowiedzi zapewnia sprytne obejście przy użyciu typów strukturalnych. Takie podejście wykorzysta refleksję za kulisami, więc możesz lub nie chcesz iść w tym kierunku. Dla Państwa przypadku użycia, to będzie wyglądać mniej więcej tak:

type useSingleArgVersion = { def thenReturn(value: AnyRef): OngoingStubbing } 
(...).asInstanceOf[useSingleArgVersion].thenReturn("something") 

Wreszcie, istnieje similar question running into a similar problem with mokito. W rzeczywistości nie zapewnia żadnych obejść, ale opisuje problem bardziej szczegółowo, jeśli interesuje Cię przyczyna takiego stanu rzeczy.

+0

, wszystko w porządku dopóki twój return nie jest AnyVal (który nie tłumaczy się na obiekt java) –

0

Próbowałem rozwiązanie Steve'a i dostał ogromny błąd kompilatora w tym:

scala.tools.nsc.symtab.Types$TypeError: type mismatch; 
found : scala.reflect.Manifest[Nothing] 
required: scala.reflect.ClassManifest[B] 
Note: Nothing <: B, but trait ClassManifest is invariant in type T. 
You may wish to investigate a wildcard type such as `_ <: B`. (SLS 3.2.10) 

udało mi się zrobić to praca z czymś takim:

thenReturn("something", Seq.empty[Object]: _*) 
0

Zakładając innymi znajdzie na to pytanie, gdy posiadający overloaded method value thenReturn with alternatives błąd, chcę również udostępnić moje rozwiązanie.

Zamiast

when(field.getValue(isA(classOf[Record]))).thenReturn(value)

używam

doReturn(value).when(field).getValue(isA(classOf[Record]))

która rozwiązuje disambiguity w moim przypadku.