Skip to content

Conversation

@jo-pol
Copy link
Contributor

@jo-pol jo-pol commented Mar 4, 2025

What this PR does / why we need it:

A dataset is not saved and there is no option to correct the mistake if you edit the “Host Dataverse” field and immediately correct and leave it. When clicking Save the page freezes and after a hard refresh all your metadata is gone and you have to start over. Reproduced in 6.3 and 6.5 (DANS branches).

A more robust solution is not to show the edit field at al when there is nothing to choose.

Which issue(s) this PR closes:

  • Closes #

Special notes for your reviewer:

Suggestions on how to test this:
There are 2 cases:

  • (two subcases) When the user can only create a dataset in one collection (or only the root collection exists) the host dataverse field shouldn't show
  • When the user has options, deleting the existing host dataverse should now result in the dataset being created in the previously selected host dataverse rather than an error occurring. Specific details on how to delete the host dataverse:
  1. In the user interface click Add Data → New Dataset
  2. The cursor is placed in the “Host Dataverse” field.
  3. Quickly type: space, back-space, tab
  4. Fill in the required fields and click Save.

Fine logging of DataverseConverter will show the name of the submitted dataverse - for a successful test this would be null/not a valid dataverse id number.

Does this PR introduce a user interface change? If mockups are available, please link/include them here:

Is there a release notes update needed for this change?:

Perhaps: the host dataverse field does not appear when there are none to choose from.

Additional documentation:

@pdurbin pdurbin moved this to Ready for Triage in IQSS Dataverse Project Mar 4, 2025
@pdurbin pdurbin added the Size: 3 A percentage of a sprint. 2.1 hours. label Mar 4, 2025
@ofahimIQSS ofahimIQSS moved this from Ready for Triage to Ready for Review ⏩ in IQSS Dataverse Project Mar 4, 2025
@qqmyers
Copy link
Member

qqmyers commented Mar 4, 2025

Can you reproduce this on demo (which is v6.5)? The code changes look OK but I haven't yet been able to trigger the problem on demo.dataverse.org.

@pdurbin
Copy link
Member

pdurbin commented Mar 5, 2025

I believe I was able to reproduce the bug on ab8110f (the latest in develop).

The page is greyed out like this:

Screenshot 2025-03-05 at 2 33 29 PM

Stacktrace:

dev_dataverse> [#|2025-03-05T19:32:37.841+0000|WARNING|Payara 6.2024.6|jakarta.enterprise.resource.webcontainer.faces.lifecycle|_ThreadID=275;_ThreadName=http-thread-pool::http-listener-1(6);_TimeMillis=1741203157841;_LevelValue=900;|
dev_dataverse>   For input string: "Root"
dev_dataverse> java.lang.NumberFormatException: For input string: "Root"
dev_dataverse> 	at java.base/java.lang.NumberFormatException.forInputString(Unknown Source)
dev_dataverse> 	at java.base/java.lang.Long.parseLong(Unknown Source)
dev_dataverse> 	at java.base/java.lang.Long.<init>(Unknown Source)
dev_dataverse> 	at edu.harvard.iq.dataverse.DataverseConverter.getAsObject(DataverseConverter.java:29)
dev_dataverse> 	at org.primefaces.component.autocomplete.AutoCompleteRenderer.getConvertedValue(AutoCompleteRenderer.java:803)
dev_dataverse> 	at jakarta.faces.component.UIInput.getConvertedValue(UIInput.java:901)
dev_dataverse> 	at jakarta.faces.component.UIInput.validate(UIInput.java:816)
dev_dataverse> 	at jakarta.faces.component.UIInput.executeValidate(UIInput.java:1093)
dev_dataverse> 	at jakarta.faces.component.UIInput.processValidators(UIInput.java:586)
dev_dataverse> 	at jakarta.faces.component.UIComponentBase.processValidators(UIComponentBase.java:907)
dev_dataverse> 	at jakarta.faces.component.UIComponentBase.processValidators(UIComponentBase.java:907)
dev_dataverse> 	at jakarta.faces.component.UIComponentBase.processValidators(UIComponentBase.java:907)
dev_dataverse> 	at jakarta.faces.component.UIForm.processValidators(UIForm.java:222)
dev_dataverse> 	at jakarta.faces.component.UIComponentBase.processValidators(UIComponentBase.java:907)
dev_dataverse> 	at jakarta.faces.component.UIComponentBase.processValidators(UIComponentBase.java:907)
dev_dataverse> 	at jakarta.faces.component.UIViewRoot.processValidators(UIViewRoot.java:1257)
dev_dataverse> 	at com.sun.faces.lifecycle.ProcessValidationsPhase.execute(ProcessValidationsPhase.java:49)
dev_dataverse> 	at com.sun.faces.lifecycle.Phase.doPhase(Phase.java:72)
dev_dataverse> 	at com.sun.faces.lifecycle.LifecycleImpl.execute(LifecycleImpl.java:159)
dev_dataverse> 	at jakarta.faces.webapp.FacesServlet.executeLifecyle(FacesServlet.java:691)
dev_dataverse> 	at jakarta.faces.webapp.FacesServlet.service(FacesServlet.java:449)
dev_dataverse> 	at org.apache.catalina.core.StandardWrapper.service(StandardWrapper.java:1554)
dev_dataverse> 	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:331)
dev_dataverse> 	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:211)
dev_dataverse> 	at org.glassfish.tyrus.servlet.TyrusServletFilter.doFilter(TyrusServletFilter.java:83)
dev_dataverse> 	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:253)
dev_dataverse> 	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:211)
dev_dataverse> 	at org.ocpsoft.rewrite.servlet.RewriteFilter.doFilter(RewriteFilter.java:226)
dev_dataverse> 	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:253)
dev_dataverse> 	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:211)
dev_dataverse> 	at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:257)
dev_dataverse> 	at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:166)
dev_dataverse> 	at org.apache.catalina.core.StandardPipeline.doInvoke(StandardPipeline.java:757)
dev_dataverse> 	at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:577)
dev_dataverse> 	at com.sun.enterprise.web.WebPipeline.invoke(WebPipeline.java:99)
dev_dataverse> 	at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:158)
dev_dataverse> 	at org.apache.catalina.connector.CoyoteAdapter.doService(CoyoteAdapter.java:372)
dev_dataverse> 	at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:239)
dev_dataverse> 	at com.sun.enterprise.v3.services.impl.ContainerMapper$HttpHandlerCallable.call(ContainerMapper.java:520)
dev_dataverse> 	at com.sun.enterprise.v3.services.impl.ContainerMapper.service(ContainerMapper.java:217)
dev_dataverse> 	at org.glassfish.grizzly.http.server.HttpHandler.runService(HttpHandler.java:174)
dev_dataverse> 	at org.glassfish.grizzly.http.server.HttpHandler.doHandle(HttpHandler.java:153)
dev_dataverse> 	at org.glassfish.grizzly.http.server.HttpServerFilter.handleRead(HttpServerFilter.java:196)
dev_dataverse> 	at org.glassfish.grizzly.filterchain.ExecutorResolver$9.execute(ExecutorResolver.java:88)
dev_dataverse> 	at org.glassfish.grizzly.filterchain.DefaultFilterChain.executeFilter(DefaultFilterChain.java:246)
dev_dataverse> 	at org.glassfish.grizzly.filterchain.DefaultFilterChain.executeChainPart(DefaultFilterChain.java:178)
dev_dataverse> 	at org.glassfish.grizzly.filterchain.DefaultFilterChain.execute(DefaultFilterChain.java:118)
dev_dataverse> 	at org.glassfish.grizzly.filterchain.DefaultFilterChain.process(DefaultFilterChain.java:96)
dev_dataverse> 	at org.glassfish.grizzly.ProcessorExecutor.execute(ProcessorExecutor.java:51)
dev_dataverse> 	at org.glassfish.grizzly.nio.transport.TCPNIOTransport.fireIOEvent(TCPNIOTransport.java:510)
dev_dataverse> 	at org.glassfish.grizzly.strategies.AbstractIOStrategy.fireIOEvent(AbstractIOStrategy.java:82)
dev_dataverse> 	at org.glassfish.grizzly.strategies.WorkerThreadIOStrategy.run0(WorkerThreadIOStrategy.java:83)
dev_dataverse> 	at org.glassfish.grizzly.strategies.WorkerThreadIOStrategy$WorkerThreadRunnable.run(WorkerThreadIOStrategy.java:101)
dev_dataverse> 	at org.glassfish.grizzly.threadpool.AbstractThreadPool$Worker.doWork(AbstractThreadPool.java:535)
dev_dataverse> 	at org.glassfish.grizzly.threadpool.AbstractThreadPool$Worker.run(AbstractThreadPool.java:515)
dev_dataverse> 	at java.base/java.lang.Thread.run(Unknown Source)
dev_dataverse> |#]
dev_dataverse> 
dev_dataverse> [#|2025-03-05T19:32:37.846+0000|SEVERE|Payara 6.2024.6|jakarta.enterprise.resource.webcontainer.faces.context|_ThreadID=275;_ThreadName=http-thread-pool::http-listener-1(6);_TimeMillis=1741203157846;_LevelValue=1000;|
dev_dataverse>   java.lang.NumberFormatException: For input string: "Root"
dev_dataverse> java.lang.NumberFormatException: For input string: "Root"
dev_dataverse> 	at java.base/java.lang.NumberFormatException.forInputString(Unknown Source)
dev_dataverse> 	at java.base/java.lang.Long.parseLong(Unknown Source)
dev_dataverse> 	at java.base/java.lang.Long.<init>(Unknown Source)
dev_dataverse> 	at edu.harvard.iq.dataverse.DataverseConverter.getAsObject(DataverseConverter.java:29)
dev_dataverse> 	at org.primefaces.component.autocomplete.AutoCompleteRenderer.getConvertedValue(AutoCompleteRenderer.java:803)
dev_dataverse> 	at jakarta.faces.component.UIInput.getConvertedValue(UIInput.java:901)
dev_dataverse> 	at jakarta.faces.component.UIInput.validate(UIInput.java:816)
dev_dataverse> 	at jakarta.faces.component.UIInput.executeValidate(UIInput.java:1093)
dev_dataverse> 	at jakarta.faces.component.UIInput.processValidators(UIInput.java:586)
dev_dataverse> 	at jakarta.faces.component.UIComponentBase.processValidators(UIComponentBase.java:907)
dev_dataverse> 	at jakarta.faces.component.UIComponentBase.processValidators(UIComponentBase.java:907)
dev_dataverse> 	at jakarta.faces.component.UIComponentBase.processValidators(UIComponentBase.java:907)
dev_dataverse> 	at jakarta.faces.component.UIForm.processValidators(UIForm.java:222)
dev_dataverse> 	at jakarta.faces.component.UIComponentBase.processValidators(UIComponentBase.java:907)
dev_dataverse> 	at jakarta.faces.component.UIComponentBase.processValidators(UIComponentBase.java:907)
dev_dataverse> 	at jakarta.faces.component.UIViewRoot.processValidators(UIViewRoot.java:1257)
dev_dataverse> 	at com.sun.faces.lifecycle.ProcessValidationsPhase.execute(ProcessValidationsPhase.java:49)
dev_dataverse> 	at com.sun.faces.lifecycle.Phase.doPhase(Phase.java:72)
dev_dataverse> 	at com.sun.faces.lifecycle.LifecycleImpl.execute(LifecycleImpl.java:159)
dev_dataverse> 	at jakarta.faces.webapp.FacesServlet.executeLifecyle(FacesServlet.java:691)
dev_dataverse> 	at jakarta.faces.webapp.FacesServlet.service(FacesServlet.java:449)
dev_dataverse> 	at org.apache.catalina.core.StandardWrapper.service(StandardWrapper.java:1554)
dev_dataverse> 	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:331)
dev_dataverse> 	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:211)
dev_dataverse> 	at org.glassfish.tyrus.servlet.TyrusServletFilter.doFilter(TyrusServletFilter.java:83)
dev_dataverse> 	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:253)
dev_dataverse> 	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:211)
dev_dataverse> 	at org.ocpsoft.rewrite.servlet.RewriteFilter.doFilter(RewriteFilter.java:226)
dev_dataverse> 	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:253)
dev_dataverse> 	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:211)
dev_dataverse> 	at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:257)
dev_dataverse> 	at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:166)
dev_dataverse> 	at org.apache.catalina.core.StandardPipeline.doInvoke(StandardPipeline.java:757)
dev_dataverse> 	at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:577)
dev_dataverse> 	at com.sun.enterprise.web.WebPipeline.invoke(WebPipeline.java:99)
dev_dataverse> 	at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:158)
dev_dataverse> 	at org.apache.catalina.connector.CoyoteAdapter.doService(CoyoteAdapter.java:372)
dev_dataverse> 	at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:239)
dev_dataverse> 	at com.sun.enterprise.v3.services.impl.ContainerMapper$HttpHandlerCallable.call(ContainerMapper.java:520)
dev_dataverse> 	at com.sun.enterprise.v3.services.impl.ContainerMapper.service(ContainerMapper.java:217)
dev_dataverse> 	at org.glassfish.grizzly.http.server.HttpHandler.runService(HttpHandler.java:174)
dev_dataverse> 	at org.glassfish.grizzly.http.server.HttpHandler.doHandle(HttpHandler.java:153)
dev_dataverse> 	at org.glassfish.grizzly.http.server.HttpServerFilter.handleRead(HttpServerFilter.java:196)
dev_dataverse> 	at org.glassfish.grizzly.filterchain.ExecutorResolver$9.execute(ExecutorResolver.java:88)
dev_dataverse> 	at org.glassfish.grizzly.filterchain.DefaultFilterChain.executeFilter(DefaultFilterChain.java:246)
dev_dataverse> 	at org.glassfish.grizzly.filterchain.DefaultFilterChain.executeChainPart(DefaultFilterChain.java:178)
dev_dataverse> 	at org.glassfish.grizzly.filterchain.DefaultFilterChain.execute(DefaultFilterChain.java:118)
dev_dataverse> 	at org.glassfish.grizzly.filterchain.DefaultFilterChain.process(DefaultFilterChain.java:96)
dev_dataverse> 	at org.glassfish.grizzly.ProcessorExecutor.execute(ProcessorExecutor.java:51)
dev_dataverse> 	at org.glassfish.grizzly.nio.transport.TCPNIOTransport.fireIOEvent(TCPNIOTransport.java:510)
dev_dataverse> 	at org.glassfish.grizzly.strategies.AbstractIOStrategy.fireIOEvent(AbstractIOStrategy.java:82)
dev_dataverse> 	at org.glassfish.grizzly.strategies.WorkerThreadIOStrategy.run0(WorkerThreadIOStrategy.java:83)
dev_dataverse> 	at org.glassfish.grizzly.strategies.WorkerThreadIOStrategy$WorkerThreadRunnable.run(WorkerThreadIOStrategy.java:101)
dev_dataverse> 	at org.glassfish.grizzly.threadpool.AbstractThreadPool$Worker.doWork(AbstractThreadPool.java:535)
dev_dataverse> 	at org.glassfish.grizzly.threadpool.AbstractThreadPool$Worker.run(AbstractThreadPool.java:515)
dev_dataverse> 	at java.base/java.lang.Thread.run(Unknown Source)
dev_dataverse> |#]

@pdurbin
Copy link
Member

pdurbin commented Mar 5, 2025

I tried again and I was able to reproduce it again.

One difference for me, perhaps, is that after a hard-reset the fields I entered are still there, with the exception of the Subject field. So I don't lose all of my work, but still, it's a very annoying user experience!

@pdurbin
Copy link
Member

pdurbin commented Mar 5, 2025

@jo-pol I switched to this branch/PR and the stacktrace looks different but I have the same behavior in the UI. The screen goes gray-ish and the dataset isn't saved.

Screenshot 2025-03-05 at 2 43 10 PM

dev_dataverse> [#|2025-03-05T19:42:38.837+0000|INFO|Payara 6.2024.6|com.ocpsoft.pretty.faces.config.spi.DefaultXMLConfigurationProvider|_ThreadID=286;_ThreadName=http-thread-pool::http-listener-1(7);_TimeMillis=1741203758837;_LevelValue=800;|
dev_dataverse>   loadConfiguration called...|#]
dev_dataverse> 
dev_dataverse> [#|2025-03-05T19:42:39.430+0000|SEVERE|Payara 6.2024.6|jakarta.enterprise.resource.webcontainer.faces.context|_ThreadID=286;_ThreadName=http-thread-pool::http-listener-1(7);_TimeMillis=1741203759430;_LevelValue=1000;|
dev_dataverse>   jakarta.faces.component.UpdateModelException: java.lang.IllegalArgumentException: Cannot convert Root of type class java.lang.String to class edu.harvard.iq.dataverse.Dataverse
dev_dataverse> jakarta.faces.component.UpdateModelException: java.lang.IllegalArgumentException: Cannot convert Root of type class java.lang.String to class edu.harvard.iq.dataverse.Dataverse
dev_dataverse> 	at jakarta.faces.component.UIInput.updateModel(UIInput.java:721)
dev_dataverse> 	at jakarta.faces.component.UIInput.processUpdates(UIInput.java:622)
dev_dataverse> 	at jakarta.faces.component.UIComponentBase.processUpdates(UIComponentBase.java:938)
dev_dataverse> 	at jakarta.faces.component.UIComponentBase.processUpdates(UIComponentBase.java:938)
dev_dataverse> 	at jakarta.faces.component.UIComponentBase.processUpdates(UIComponentBase.java:938)
dev_dataverse> 	at jakarta.faces.component.UIForm.processUpdates(UIForm.java:253)
dev_dataverse> 	at jakarta.faces.component.UIComponentBase.processUpdates(UIComponentBase.java:938)
dev_dataverse> 	at jakarta.faces.component.UIComponentBase.processUpdates(UIComponentBase.java:938)
dev_dataverse> 	at jakarta.faces.component.UIViewRoot.processUpdates(UIViewRoot.java:1305)
dev_dataverse> 	at com.sun.faces.lifecycle.UpdateModelValuesPhase.execute(UpdateModelValuesPhase.java:50)
dev_dataverse> 	at com.sun.faces.lifecycle.Phase.doPhase(Phase.java:72)
dev_dataverse> 	at com.sun.faces.lifecycle.LifecycleImpl.execute(LifecycleImpl.java:159)
dev_dataverse> 	at jakarta.faces.webapp.FacesServlet.executeLifecyle(FacesServlet.java:691)
dev_dataverse> 	at jakarta.faces.webapp.FacesServlet.service(FacesServlet.java:449)
dev_dataverse> 	at org.apache.catalina.core.StandardWrapper.service(StandardWrapper.java:1554)
dev_dataverse> 	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:331)
dev_dataverse> 	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:211)
dev_dataverse> 	at org.glassfish.tyrus.servlet.TyrusServletFilter.doFilter(TyrusServletFilter.java:83)
dev_dataverse> 	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:253)
dev_dataverse> 	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:211)
dev_dataverse> 	at org.ocpsoft.rewrite.servlet.RewriteFilter.doFilter(RewriteFilter.java:226)
dev_dataverse> 	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:253)
dev_dataverse> 	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:211)
dev_dataverse> 	at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:257)
dev_dataverse> 	at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:166)
dev_dataverse> 	at org.apache.catalina.core.StandardPipeline.doInvoke(StandardPipeline.java:757)
dev_dataverse> 	at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:577)
dev_dataverse> 	at com.sun.enterprise.web.WebPipeline.invoke(WebPipeline.java:99)
dev_dataverse> 	at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:158)
dev_dataverse> 	at org.apache.catalina.connector.CoyoteAdapter.doService(CoyoteAdapter.java:372)
dev_dataverse> 	at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:239)
dev_dataverse> 	at com.sun.enterprise.v3.services.impl.ContainerMapper$HttpHandlerCallable.call(ContainerMapper.java:520)
dev_dataverse> 	at com.sun.enterprise.v3.services.impl.ContainerMapper.service(ContainerMapper.java:217)
dev_dataverse> 	at org.glassfish.grizzly.http.server.HttpHandler.runService(HttpHandler.java:174)
dev_dataverse> 	at org.glassfish.grizzly.http.server.HttpHandler.doHandle(HttpHandler.java:153)
dev_dataverse> 	at org.glassfish.grizzly.http.server.HttpServerFilter.handleRead(HttpServerFilter.java:196)
dev_dataverse> 	at org.glassfish.grizzly.filterchain.ExecutorResolver$9.execute(ExecutorResolver.java:88)
dev_dataverse> 	at org.glassfish.grizzly.filterchain.DefaultFilterChain.executeFilter(DefaultFilterChain.java:246)
dev_dataverse> 	at org.glassfish.grizzly.filterchain.DefaultFilterChain.executeChainPart(DefaultFilterChain.java:178)
dev_dataverse> 	at org.glassfish.grizzly.filterchain.DefaultFilterChain.execute(DefaultFilterChain.java:118)
dev_dataverse> 	at org.glassfish.grizzly.filterchain.DefaultFilterChain.process(DefaultFilterChain.java:96)
dev_dataverse> 	at org.glassfish.grizzly.ProcessorExecutor.execute(ProcessorExecutor.java:51)
dev_dataverse> 	at org.glassfish.grizzly.nio.transport.TCPNIOTransport.fireIOEvent(TCPNIOTransport.java:510)
dev_dataverse> 	at org.glassfish.grizzly.strategies.AbstractIOStrategy.fireIOEvent(AbstractIOStrategy.java:82)
dev_dataverse> 	at org.glassfish.grizzly.strategies.WorkerThreadIOStrategy.run0(WorkerThreadIOStrategy.java:83)
dev_dataverse> 	at org.glassfish.grizzly.strategies.WorkerThreadIOStrategy$WorkerThreadRunnable.run(WorkerThreadIOStrategy.java:101)
dev_dataverse> 	at org.glassfish.grizzly.threadpool.AbstractThreadPool$Worker.doWork(AbstractThreadPool.java:535)
dev_dataverse> 	at org.glassfish.grizzly.threadpool.AbstractThreadPool$Worker.run(AbstractThreadPool.java:515)
dev_dataverse> 	at java.base/java.lang.Thread.run(Unknown Source)
dev_dataverse> Caused by: java.lang.IllegalArgumentException: Cannot convert Root of type class java.lang.String to class edu.harvard.iq.dataverse.Dataverse
dev_dataverse> 	at org.glassfish.expressly.lang.ELSupport.coerceToType(ELSupport.java:482)
dev_dataverse> 	at org.glassfish.expressly.lang.ELSupport.coerceToType(ELSupport.java:423)
dev_dataverse> 	at org.glassfish.expressly.parser.AstValue.setValue(AstValue.java:191)
dev_dataverse> 	at org.glassfish.expressly.ValueExpressionImpl.setValue(ValueExpressionImpl.java:184)
dev_dataverse> 	at org.jboss.weld.module.web.el.WeldValueExpression.setValue(WeldValueExpression.java:64)
dev_dataverse> 	at com.sun.faces.facelets.el.TagValueExpression.setValue(TagValueExpression.java:95)
dev_dataverse> 	at jakarta.faces.component.UIInput.updateModel(UIInput.java:696)
dev_dataverse> 	... 48 more
dev_dataverse> |#]
dev_dataverse> 

@pdurbin pdurbin self-assigned this Mar 5, 2025
@pdurbin pdurbin moved this from Ready for Review ⏩ to In Review 🔎 in IQSS Dataverse Project Mar 5, 2025
@qqmyers
Copy link
Member

qqmyers commented Mar 5, 2025

FWIW: Looks like it only occurs when there are no templates for some reason.

@jo-pol
Copy link
Contributor Author

jo-pol commented Mar 6, 2025

@pdurbin
1: what do you mean with a hard-reset? cc @janvanmansum
2: I actually tested the code changes on a VM box with v6.5 and some patches https://github.com/DANS-KNAW/dataverse/tree/v6.5-DANS-DataStation

@jo-pol
Copy link
Contributor Author

jo-pol commented Mar 6, 2025

Tried the IQSS develop branch on a DANS v6.5 VM and got an internal DB error.

@pdurbin
Copy link
Member

pdurbin commented Mar 6, 2025

@jo-pol sorry, I was trying to use the same terminology you were. I said "hard reset" when I meant "hard refresh".

What was the internal DB error? 🤔

@jo-pol
Copy link
Contributor Author

jo-pol commented Mar 6, 2025

The DB error was

Internal Exception: org.postgresql.util.PSQLException: ERROR: column "displayoncreate" does not exist
  Position: 12
Error Code: 0
Call: SELECT ID, DISPLAYONCREATE, INCLUDE, REQUIRED, datasetfieldtype_id, dataverse_id FROM DataverseFieldTypeInputLevel WHERE (dataverse_id = ?)
	bind => [1 parameter bound]
Query: ReadAllQuery(name="dataverseFieldTypeInputLevels" referenceClass=DataverseFieldTypeInputLevel sql="SELECT ID, DISPLAYONCREATE, INCLUDE, REQUIRED, datasetfieldtype_id, dataverse_id FROM DataverseFieldTypeInputLevel WHERE (dataverse_id = ?)")

@jo-pol
Copy link
Contributor Author

jo-pol commented Mar 6, 2025

Tried returning null in stead of a string also worked on a DANS v6.5 VM. Examining the stack trace and corresponding jakarta/faces code that would cause a null pointer exception on IQSS development. So now I used zero as default. Don't know about the effects on templates and/or when the initial dataverse was another one.

@jo-pol
Copy link
Contributor Author

jo-pol commented Mar 6, 2025

Not sure but I might have stayed on the page https://dev.archaeology.datastations.nl/dataset.xhtml?ownerId=1 when redeploying the war when I saw the DB error.

@pdurbin
Copy link
Member

pdurbin commented Mar 6, 2025

ERROR: column "displayoncreate" does not exist

Right, sorry, that was our bad. Fixed in this PR:

@cmbz cmbz added FY25 Sprint 19 FY25 Sprint 19 (2025-03-12 - 2025-03-26) FY25 Sprint 18 FY25 Sprint 18 (2025-02-26 - 2025-03-12) labels Mar 12, 2025
@pdurbin
Copy link
Member

pdurbin commented Mar 19, 2025

@jo-pol we just released Dataverse 6.6. Can you please merge the latest from develop into this branch?

Also, as I said above, I can definitely reproduce some strangeness but this pull request doesn't seem to help (the error in server.log was different). Am I missing something? Thanks!

@jo-pol
Copy link
Contributor Author

jo-pol commented Mar 25, 2025

@pdurbin
Did you retry after the commit using zero as default search argument?

@coveralls
Copy link

coveralls commented Mar 25, 2025

Coverage Status

coverage: 23.145% (+0.4%) from 22.734%
when pulling a9ca7bb on DANS-KNAW-jp:blocked-deposit-page
into efbbd18 on IQSS:develop.

@pdurbin pdurbin changed the title blocked deposit page blocked deposit page, hide host field when only one collection (e.g. root) Mar 25, 2025
@jo-pol jo-pol requested a review from qqmyers June 3, 2025 13:44
@cmbz cmbz added the FY25 Sprint 25 FY25 Sprint 25 (2025-06-04 - 2025-06-18) label Jun 4, 2025
jo-pol added a commit to DANS-KNAW/dataverse that referenced this pull request Jun 5, 2025
Copy link
Member

@qqmyers qqmyers left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK - I think this looks good now (haven't tested the latest changes) except that the release note needs to be updated again (the default is the original dataverse not root now). I'll go ahead and approve so this can get into QA.

@github-project-automation github-project-automation bot moved this from In Review 🔎 to Ready for QA ⏩ in IQSS Dataverse Project Jun 5, 2025
@qqmyers qqmyers removed their assignment Jun 5, 2025
@ofahimIQSS ofahimIQSS self-assigned this Jun 5, 2025
@ofahimIQSS ofahimIQSS moved this from Ready for QA ⏩ to QA ✅ in IQSS Dataverse Project Jun 5, 2025
@ofahimIQSS
Copy link
Contributor

Fix looks good! Merging.

@ofahimIQSS ofahimIQSS merged commit 7851e83 into IQSS:develop Jun 16, 2025
16 checks passed
@github-project-automation github-project-automation bot moved this from QA ✅ to Merged 🚀 in IQSS Dataverse Project Jun 16, 2025
@ofahimIQSS ofahimIQSS removed their assignment Jun 16, 2025
@pdurbin pdurbin moved this from Merged 🚀 to Done 🧹 in IQSS Dataverse Project Jun 16, 2025
@pdurbin pdurbin added this to the 6.7 milestone Jun 16, 2025
@jp-tosca jp-tosca requested a review from Copilot July 30, 2025 15:11
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR fixes a critical bug where users could lose their dataset metadata when editing the "Host Dataverse" field. The solution involves hiding the host dataverse field when there's only one collection available and providing better error handling when the field is cleared accidentally.

  • Hides the host dataverse field in CREATE mode when there's only one dataverse to choose from
  • Adds robust error handling in DataverseConverter to prevent crashes when invalid values are submitted
  • Includes release notes documenting the user-facing improvements

Reviewed Changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 3 comments.

File Description
src/main/webapp/dataset.xhtml Conditionally renders host dataverse field only when multiple dataverses exist
src/main/java/edu/harvard/iq/dataverse/DataverseConverter.java Adds validation and fallback logic for invalid dataverse submissions
src/main/java/edu/harvard/iq/dataverse/DatasetPage.java Implements method to check if multiple dataverses are available for selection
doc/release-notes/11301-blocked-deposit-page.md Documents the bug fix and user-facing improvements

}

public boolean isHasDataversesToChoose() {
this.hasDataversesToChoose = dataverseService.findAll().size() > 1;
Copy link

Copilot AI Jul 30, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The method isHasDataversesToChoose() calls dataverseService.findAll().size() every time it's invoked, which could be expensive if there are many dataverses. Consider caching this value or using a more efficient query to count dataverses.

Suggested change
this.hasDataversesToChoose = dataverseService.findAll().size() > 1;
this.hasDataversesToChoose = dataverseService.countDataverses() > 1;

Copilot uses AI. Check for mistakes.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

DataverseServiceBean.getDataverseCount() exists and could be used here. - countDataverses() doesn't exist.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@qqmyers mised these comment so far. Got another suggestion form copilot, perhaps more elaborate to implement but might be more effiecient

Query q = em.createQuery("SELECT 1 FROM Dataverse d");
q.setMaxResults(1);
boolean exists = !q.getResultList().isEmpty();

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm - with maxResults set to one, you'd never know if there was more than one (thanks Copilot!), but I guess it could be limited to 2 instead.
That said, I think they key thing is to avoid getting a list of objects - that's a big expense.

From a quick test, getting two rows is cheaper than getting the count, but both are orders of magnitude less than getting the objects.

I guess since limiting to 2 rows will scale better than getting the count, I guess this approach makes more sense if you're willing to implement it.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just logged the duration on a VM with almost 100K dataverses

findall: PT15.632S
getDataverseCount: PT-0.026S

Looks good enough with less effort.

*/
@FacesConverter("dataverseConverter")
public class DataverseConverter implements Converter {
private static final Logger logger = Logger.getLogger(DatasetPage.class.getCanonicalName());
Copy link

Copilot AI Jul 30, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The logger is incorrectly configured to use DatasetPage.class.getCanonicalName() instead of DataverseConverter.class.getCanonicalName(). This will cause log messages to appear as if they're coming from DatasetPage rather than DataverseConverter.

Suggested change
private static final Logger logger = Logger.getLogger(DatasetPage.class.getCanonicalName());
private static final Logger logger = Logger.getLogger(DataverseConverter.class.getCanonicalName());

Copilot uses AI. Check for mistakes.
return CDI.current().select(DatasetPage.class).get().getSelectedHostDataverse();
}
else {
return dataverseService.find(Long.valueOf(submittedValue));
Copy link

Copilot AI Jul 30, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using Long.valueOf() can throw NumberFormatException even though the regex check should prevent this. However, the regex [0-9]+ doesn't account for potential overflow of Long values. Consider using Long.parseLong() with proper exception handling or add bounds checking.

Suggested change
return dataverseService.find(Long.valueOf(submittedValue));
try {
return dataverseService.find(Long.parseLong(submittedValue));
} catch (NumberFormatException e) {
logger.severe("Submitted value is out of range for a Long: " + submittedValue);
return null;
}

Copilot uses AI. Check for mistakes.
pdurbin added a commit that referenced this pull request Jul 30, 2025
pdurbin added a commit that referenced this pull request Jul 30, 2025
With the wrong line, the "host dataverse" field wasn't
working at all!
ofahimIQSS added a commit that referenced this pull request Jul 31, 2025
@cmbz cmbz added the FY26 Sprint 4 FY26 Sprint 4 (2025-08-13 - 2025-08-27) label Aug 16, 2025
@qqmyers
Copy link
Member

qqmyers commented Aug 20, 2025

@jo-pol - I don't know if you saw, but this PR was reverted in #11700 after it was discovered that the query you added caused a massive slowdown on the create dataset page at Harvard (where there are thousands of collections) - see #11698 for details. If you think all or part of this should get into v6.8, you should submit a new PR. (I haven't tested but I think the getDataverseCount() query noted in the comments above, and caching it's value after the first call as suggested in https://guides.dataverse.org/en/latest/developers/tips.html#avoiding-inefficiencies-in-jsf-render-logic would probably solve the performance issue.) Others were more involved in investigating this - feel free to reach out if you have questions.

@cmbz cmbz removed the FY26 Sprint 4 FY26 Sprint 4 (2025-08-13 - 2025-08-27) label Aug 20, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

FY25 Sprint 18 FY25 Sprint 18 (2025-02-26 - 2025-03-12) FY25 Sprint 19 FY25 Sprint 19 (2025-03-12 - 2025-03-26) FY25 Sprint 20 FY25 Sprint 20 (2025-03-26 - 2025-04-09) FY25 Sprint 21 FY25 Sprint 21 (2025-04-09 - 2025-04-23) FY25 Sprint 22 FY25 Sprint 22 (2025-04-23 - 2025-05-07) FY25 Sprint 23 FY25 Sprint 23 (2025-05-07 - 2025-05-21) FY25 Sprint 24 FY25 Sprint 24 (2025-05-21 - 2025-06-04) FY25 Sprint 25 FY25 Sprint 25 (2025-06-04 - 2025-06-18) Size: 3 A percentage of a sprint. 2.1 hours.

Projects

Status: Done 🧹

Development

Successfully merging this pull request may close these issues.

6 participants