Im stumped. I declare my set thusly:
private Set<Long> applicationIds;
Then I populate it like this:
public void setApplicationIds( Set<Long> applicationIds ) {
this.applicationIds = new TreeSet<Long>( applicationIds );
this.applications = null;
}
Then I attempt to use it:
public List<Application> getApplications() {
if ( applications == null ) {
applications = new ArrayList<Application>();
if ( applicationIds != null ) {
for ( Application application : availableApplications ) {
if ( applicationIds.contains( Long.valueOf( application.getId() ) ) ) {
applications.add( application );
}
}
}
}
return applications;
}
And I end up with this:
java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Long
at java.lang.Long.compareTo(Long.java:50)
at java.util.TreeMap.getEntry(TreeMap.java:346)
at java.util.TreeMap.containsKey(TreeMap.java:227)
at java.util.TreeSet.contains(TreeSet.java:234)
at org.mitre.asias.pf.pnp.viewmodel.Subscription.getApplications(Subscription.java:84)
The line causing the exception (line 84 from the stack trace) is this one:
if ( applicationIds.contains( Long.valueOf( application.getId() ) ) ) {
Perhaps I am missing something, but if the declaration is Set<Long>
and I am calling the contains
method passing in a Long.valueOf
value, how can I be getting this exception?
This is a model bean for a JSF application. I am using Java 6, Tomcat 6.0.32, mojarra 2.1.14, but none of that should really matter as the Generics are supposed to prevent this kind of problem compile time...
-------------- EDIT -----------------
Its actually the JSF... I threw together a super simplified example with this setter:
public void setSelectedValues(Set<Long> selectedValues) {
this.selectedValues = selectedValues;
if (logger.isTraceEnabled()) {
StringBuilder message = new StringBuilder("Selected values:");
for (Object value : selectedValues) {
message.append("\n\t'").append(value.getClass().getName())
.append("': '").append(value.toString()).append("'");
}
logger.trace(message.toString());
}
this.selections = null;
}
bound to this component:
<p:selectManyCheckbox id="numbers"
value="#{controller.selectedValues}" layout="pageDirection">
<f:selectItems value="#{controller.availableValues}" />
</p:selectManyCheckbox>
which writes this to the log:
15:45:16.887 [http-bio-8080-exec-9] TRACE com.pastdev.learn.debug.Controller - Selected values:
'java.lang.String': '1'
'java.lang.String': '5'
So, the simple answer is the correct one (thank you @PaulTomblin for emphasizing this). The setter is getting called with a Set
that contains String
s. So now, what is the best process for conversion? Will I need to iterate through the list casting each value to a Long?
As a side note, I tested this on Tomcat 7 using Java 7 and the ClassCastException went away, however, the contains
method always returns false
as should be expected.
-------------- EDIT 2 -----------------
I found an answer with the correct way to bind my component here.
-------------- EDIT 3 -----------------
And here is a better explanation of the problem.
OK @Lucas I just gave a try using quick and dirty code using the code you posted as part of the question and it works fine. May be you need to check your
Application
class once more.}
And:
Note that in Java, generic type annotations are only hints for the compiler and have no effect at runtime, so it is possible to violate these constraints at runtime (but there will be a compiler warning somewhere).
Looks like your
Set<Long>
actually contains at least one String. Where is that Set coming from?Yes, there should be a warning somewhere in your code about missing generic types or unchecked casts. It is only a warning because generics are optional. In the places where you did use them, it would have been an error.