java.lang.ClassCastException: [B > cannot be cast to java.lang.String
public Login authenticate(Login login) {
try {
MessageDigest md = MessageDigest.getInstance("SHA-256");
String password = login.getPassword();
try {
md.update(password.getBytes("UTF-16"));
byte[] digest = md.digest();
String query = "SELECT L FROM Login AS L WHERE L.email=? AND L.password=?";
Object[] parameters = { login.getEmail(), digest };
List<Login> resultsList = (getHibernateTemplate().find(query,parameters));
if (resultsList.isEmpty()) {
//error dude
}
else if (resultsList.size() > 1) {
//throw expections
}
else {
Login login1 = (Login) resultsList.get(0);
return login1;
开发者_开发知识库 }
} catch (UnsupportedEncodingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} catch (NoSuchAlgorithmException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
Exception
> java.lang.ClassCastException: [B
> cannot be cast to java.lang.String
> at org.hibernate.type.StringType.toString(StringType.java:44)
> at org.hibernate.type.NullableType.nullSafeToString(NullableType.java:93)
> at org.hibernate.type.NullableType.nullSafeSet(NullableType.java:140)
> at org.hibernate.type.NullableType.nullSafeSet(NullableType.java:116)
> at org.hibernate.param.PositionalParameterSpecification.bind(PositionalParameterSpecification.java:39)
> at org.hibernate.loader.hql.QueryLoader.bindParameterValues(QueryLoader.java:491)
> at org.hibernate.loader.Loader.prepareQueryStatement(Loader.java:1563)
> at org.hibernate.loader.Loader.doQuery(Loader.java:673)
> at org.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java:236)
> at org.hibernate.loader.Loader.doList(Loader.java:2213)
> at org.hibernate.loader.Loader.listIgnoreQueryCache(Loader.java:2104)
> at org.hibernate.loader.Loader.list(Loader.java:2099)
> at org.hibernate.loader.hql.QueryLoader.list(QueryLoader.java:378)
> at org.hibernate.hql.ast.QueryTranslatorImpl.list(QueryTranslatorImpl.java:338)
> at org.hibernate.engine.query.HQLQueryPlan.performList(HQLQueryPlan.java:172)
> at org.hibernate.impl.SessionImpl.list(SessionImpl.java:1121)
> at org.hibernate.impl.QueryImpl.list(QueryImpl.java:79)
> at org.springframework.orm.hibernate3.HibernateTemplate$29.doInHibernate(HibernateTemplate.java:856)
> at org.springframework.orm.hibernate3.HibernateTemplate.execute(HibernateTemplate.java:373)
> at org.springframework.orm.hibernate3.HibernateTemplate.find(HibernateTemplate.java:847)
> at com.intermedix.services.LoginService.authenticate(LoginService.java:30)
> at sun.reflect.NativeMethodAccessorImpl.invoke0(Native
> Method)
> at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
> at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
> at java.lang.reflect.Method.invoke(Method.java:597)
> at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:301)
> at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:182)
> at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:149)
> at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:106)
> at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:171)
> at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:204)
> at $Proxy31.authenticate(Unknown Source)
> at com.intermedix.ui.LoginDailog.checkLogin(LoginDailog.java:106)
> at com.intermedix.ui.LoginDailog.access$0(LoginDailog.java:102)
> at com.intermedix.ui.LoginDailog$2.handleAction(LoginDailog.java:88)
> at com.vaadin.event.ActionManager.handleAction(ActionManager.java:228)
> at com.vaadin.event.ActionManager.handleActions(ActionManager.java:198)
> at com.vaadin.ui.Panel.changeVariables(Panel.java:345)
> at com.vaadin.ui.Window.changeVariables(Window.java:1073)
> at com.vaadin.terminal.gwt.server.AbstractCommunicationManager.handleVariables(AbstractCommunicationManager.java:1094)
> at com.vaadin.terminal.gwt.server.AbstractCommunicationManager.doHandleUidlRequest(AbstractCommunicationManager.java:590)
> at com.vaadin.terminal.gwt.server.CommunicationManager.handleUidlRequest(CommunicationManager.java:266)
> at com.vaadin.terminal.gwt.server.AbstractApplicationServlet.service(AbstractApplicationServlet.java:476)
> at javax.servlet.http.HttpServlet.service(HttpServlet.java:820)
> at org.mortbay.jetty.servlet.ServletHolder.handle(ServletHolder.java:511)
> at org.mortbay.jetty.servlet.ServletHandler.handle(ServletHandler.java:390)
> at org.mortbay.jetty.security.SecurityHandler.handle(SecurityHandler.java:216)
> at org.mortbay.jetty.servlet.SessionHandler.handle(SessionHandler.java:182)
> at org.mortbay.jetty.handler.ContextHandler.handle(ContextHandler.java:765)
> at org.mortbay.jetty.webapp.WebAppContext.handle(WebAppContext.java:418)
> at org.mortbay.jetty.handler.ContextHandlerCollection.handle(ContextHandlerCollection.java:230)
> at org.mortbay.jetty.handler.HandlerCollection.handle(HandlerCollection.java:114)
> at org.mortbay.jetty.handler.HandlerWrapper.handle(HandlerWrapper.java:152)
> at org.mortbay.jetty.Server.handle(Server.java:326)
> at org.mortbay.jetty.HttpConnection.handleRequest(HttpConnection.java:542)
> at org.mortbay.jetty.HttpConnection$RequestHandler.content(HttpConnection.java:943)
> at org.mortbay.jetty.HttpParser.parseNext(HttpParser.java:756)
> at org.mortbay.jetty.HttpParser.parseAvailable(HttpParser.java:218)
> at org.mortbay.jetty.HttpConnection.handle(HttpConnection.java:404)
> at org.mortbay.io.nio.SelectChannelEndPoint.run(SelectChannelEndPoint.java:410)
> at org.mortbay.thread.QueuedThreadPool$PoolThread.run(QueuedThreadPool.java:582)
Seems the password column of your database is a type mapped as a String
in Java (varchar
most probably). So hibernate cannot convert your byte array
to a String
.
You can change your lines to something like:
String digest = new String(md.digest());
String query = "SELECT L FROM Login AS L WHERE L.email=? AND L.password=?";
Object[] parameters = { login.getEmail(), digest };
But it probably won't work as the digest will most certainly contain bytes not mappable to chars regardless of the encoding. You should probably use a base64 encoding to map you binary blob to a String.
Another solution will be to change your dabase scheme and make the password
field a binary rather than a varchar
.
In both cases you need to know how the password
field is inserted in the database.
Some remarks on your code:
I find strange that you check the password by selecting a row from your database with both the username and the password. I'd though more logical to select using only the user and then validate the supplied password against the one returned on the database.
You use a hash function to ensure your password won't be stored in plain text in the database. That's good. However your scheme has a big flaw: if several users have the same password then the hashed password will be the same in the database. So if you have access to the database and know the password of one user it'll be really easy to find all the users sharing this password. In order to build something more secure you should use a password encoding scheme that include some salt.
looks like you're [passing a byte array where a string was required.
try { login.getEmail(), new String(digest) };
instead of { login.getEmail(), digest };
refer http://download.oracle.com/javase/1.4.2/docs/api/java/lang/String.html#String%28byte[]%29
The error seems to be in line 30, which I am guessing is the Object[]
parameters line. In which case you need to convert the byte[]
digest to String and use the string as the parameter.
this answer was given before the question was edited.
wrap things up in functions:
byte[] digest = getMessageDigest(login.getPassword());
login1 = verifyPassword(login.getEmail(), digest);
of course the relevant try
/catch
are still there.
Try to move away from the habit e.printStackTrace()
to writing to log files with java.utils.logging.Logger or log4j.
try to have only one return in the function. if you keep the code the same, define Login login1=null
at the start of the function, and simply assign in the else block. The return at the end should be return login1
(which would be null or some value).
the parts where you have code still to be implemented (e.g. error dude) should be commented with //TODO:
. Most ides like eclipse/netbeans automatically find these comments as tasks.
Related to this error. In my case, I was mocking the String class in my test.
I had:
mockkStatic(Base64::class)
every { String(Base64.decode(text, 0)) } returns token
I changed it to:
mockkStatic(Base64::class)
every { Base64.decode(text, 0) } returns token.toByteArray()
So the String
class behaved the way needed.
精彩评论