CDV ❯ Update com.tc.exception.TCNonPortableObjectError Message (was: Proxies and AOP make clustering Spring applications arcane)
-
Bug
-
Status: Resolved
-
2 Major
-
Resolution: Cannot Reproduce
-
Sample Apps,SpringRuntime
-
-
gbevin
-
Reporter: gbevin
-
August 08, 2008
-
0
-
Watchers: 2
-
December 18, 2012
-
August 31, 2012
Description
NOTE: This BUG now refers to updating the nonportable (non-portable) error message.
Consider this class:
public class UserDetailsWrapper implements UserDetails { private final StandardAuthoritiesService service; private final User delegate;
public UserDetailsWrapper(final StandardAuthoritiesService service, final User delegate) { this.service = service; this.delegate = delegate; } // … }
When this enters a clustered graph, the service field is clustered by default. However, you might not want to cluster it if the Spring bean for the service isn’t clustered. Terracotta will spit out a TCNonPortableObjectError like the one below if an instance of UserDetailsWrapper is for example stored in a clustered session. Nothing whatshowever in this output refers to the class above, hence making it virtually impossible for the user to know what to do. They will just add JdkDynamicAopProxy to the included classes and start to pull in any possible class that is used by the service and Spring AOP. This actually happened to me and it took me hours of searching and backing up to figure out where to cut the shared graph.
From the output below it’s almost impossible to figure out that the right course of action is adding the following configuration snippet:
[INFO] [cargo0] com.tc.exception.TCNonPortableObjectError:
[INFO] [cargo0] *******************************************************************************
[INFO] [cargo0] Attempt to share an instance of a non-portable class referenced by a portable class. This
[INFO] [cargo0] unshareable class has not been included for sharing in the configuration.
[INFO] [cargo0]
[INFO] [cargo0] For more information on this issue, please visit our Troubleshooting Guide at:
[INFO] [cargo0] http://terracotta.org/kit/troubleshooting
[INFO] [cargo0]
[INFO] [cargo0] Referring class : $Proxy20
[INFO] [cargo0] Thread : http-8080-1
[INFO] [cargo0] JVM ID : VM(1)
[INFO] [cargo0] Non-included class: org.springframework.aop.framework.JdkDynamicAopProxy
[INFO] [cargo0]
[INFO] [cargo0] Action to take:
[INFO] [cargo0]
[INFO] [cargo0] 1) Reconfigure to include the unshareable classes
[INFO] [cargo0] * edit your tc-config.xml file
[INFO] [cargo0] * locate the
Comments
Tim Eck 2008-08-08
Fiona OShea 2008-08-11
Part of fix the error messages
Taylor Gautier 2008-08-14
Change the message to this:
com.tc.exception.TCNonPortableObjectError: ******************************************************************************* Attempt to share an instance of a non-portable class referenced by a portable class. This unshareable class has not been included for sharing in the configuration.
For more information on this issue, please visit our Troubleshooting Guide at: http://terracotta.org/kit/troubleshooting
Under most circumstances, you should only be adding classes for your application. If you are adding classes for frameworks or code not written by you, then you should consider finding a Terracotta Integration Module (TIM) that matches the framework you are using.
As an example, if the non-portable class listed below is net.sf.ehcache.CacheManager, you should consider using the ehcache TIM.
It is also possible that some or all of the classes above are truly non-portable, the solution is then to mark the referring field as transient. For more information on non-portable classes see the Troubleshooting Guide.
Otherwise, follow the instructions listed in the remainder of this message.
Referring class : $Proxy20 Thread : http-8080-1 JVM ID : VM(1) Non-included class: org.springframework.aop.framework.JdkDynamicAopProxy
Action to take:
1) Reconfigure to include the unshareable classes
* edit your tc-config.xml file
* locate the
* if there is already an <instrumented-classes> element present, simply add
the new includes inside it
*******************************************************************************
Taylor Gautier 2008-08-14
Please update the message.
Alex Miller 2008-08-15
I think these comments have gone in the wrong direction. The problem is that the error message is pointing in completely the wrong direction. Adding JdkDynamicAopProxy will just take you down a rabbit hole of non-portable objects and non-included classes.
I think Geert’s point is that our Spring clustering should anticipate this issue and have built-in support so this doesn’t occur. This requires re-thinking how Spring support is done in tandem with Spring AOP. So, this is not an error message problem, it’s a product strategy issue.
Fiona OShea 2008-08-18
split into 2 bugs. 1 for messaging, 1 for product issue
Fiona OShea 2008-08-25
change message for 2.7 created CDV-858 to track the product issue
Fiona OShea 2008-08-26
verify that error message is true.
nadeem ghani 2008-08-27
Not positive that I’ve tested this correctly, so spelling out steps for sanity check:
Start with DefaultBootstrapService.java in Lassen app Change type of bootstrapMonitor from Object to (new class) CDV834 run mvn tc:run
[INFO] [cargo1] org.springframework.beans.factory.BeanCreationException: Error creating bean with name ‘bootstrapService’ defined in ServletContext resource [/WEB-INF/config/domain-services.xml]: Instantiation of bean failed; nested exception is org.springframework.beans.BeanInstantiationException: Could not instantiate bean class [org.terracotta.reference.exam.service.impl.DefaultBootstrapService]: Constructor threw exception; nested exception is com.tc.exception.TCNonPortableObjectError:
[WARNING] [cargo1]
[INFO] [cargo1] *******************************************************************************
[INFO] [cargo1] Attempt to share an instance of a non-portable class by assigning it to a root. This unshareable
[INFO] [cargo1] class has not been included for sharing in the configuration.
[INFO] [cargo1]
[INFO] [cargo1] For more information on this issue, please visit our Troubleshooting Guide at:
[INFO] [cargo1] http://terracotta.org/kit/troubleshooting
[INFO] [cargo1]
[INFO] [cargo1] Thread : main
[INFO] [cargo1] JVM ID : VM(0)
[INFO] [cargo1] Non-portable root name: org.terracotta.reference.exam.service.impl.DefaultBootstrapService.bootstrapMonitor
[WARNING] [cargo1] Action to take:
[INFO] [cargo1] Non-included class : org.terracotta.reference.exam.service.impl.CDV834
[INFO] [cargo1]
[INFO] [cargo1] Under most circumstances, you should only be adding classes for your
[INFO] [cargo1] application. If you are adding classes for frameworks or code not written by
[INFO] [cargo1] you, then you should consider finding a Terracotta Integration Module (TIM)
[INFO] [cargo1] that matches the framework you are using.
[INFO] [cargo1]
[INFO] [cargo1] As an example, if the non-portable class listed below is
[INFO] [cargo1] net.sf.ehcache.CacheManager, you should consider using the ehcache TIM.
[INFO] [cargo1]
[INFO] [cargo1] It is also possible that some or all of the classes above are truly
[INFO] [cargo1] non-portable, the solution is then to mark the referring field as transient.
[INFO] [cargo1] For more information on non-portable classes see the Troubleshooting Guide.
[INFO] [cargo1]
[INFO] [cargo1] Action to take:
[INFO] [cargo1]
[INFO] [cargo1] 1) Reconfigure to include the unshareable classes
[INFO] [cargo1] * edit your tc-config.xml file
[INFO] [cargo1] * locate the
Taylor Gautier 2008-10-27
The message appears incorrect to me - the ordering of the text is incorrect compared to what I wrote.
ilevy 2008-12-10
Here’s the refactored NPOE message (shown with example values are shown for Referring class, Thread, JVM ID, and Non-portable class):
CLASS_NOT_ADAPTABLE, SUPER_CLASS_NOT_ADAPTABLE, SUBCLASS_OF_LOGICALLY_MANAGED_CLASS This class (or one of its superclasses) cannot be shared.
Possible actions to take:
-> Refactor your code to avoid sharing the unshareable class.
-> Mark the unshareable class transient in the
CLASS_NOT_IN_BOOT_JAR This class has not been configured for sharing (and must be added to the boot-jar).
Possible actions to take:
-> If this class can be made portable, add it to the Terracotta boot JAR:
1. Add this class to the
-> If this class cannot be made portable, do one of the following:
* Refactor your code to avoid sharing this class.
* Mark this class transient in the
CLASS_NOT_INCLUDED_IN_CONFIG, SUPER_CLASS_NOT_INSTRUMENTED This class (or one of its superclasses) has not been configured for sharing.
Possible actions to take:
-> If the non-portable class is part of your native code, add it to the
Terracotta configuration file (tc-config.xml by default):
1. Locate the
-> If the non-portable class is part of a framework or other 3rd-party source, try to avoid adding it to the Terracotta configuration file. Instead, consider doing one of the following:
1. Refactor your code to avoid sharing this class.
2. Use a Terracotta Integration Module. For example, if the non-portable
class listed below is net.sf.ehcache.CacheManager, use the EHCache TIM.
3. Mark this class transient in the
Alex Miller 2008-12-15
Some quick comments:
1) “Mark the unshareable class transient” (in all cases) –> seems like “class” here should be “field”. Maybe most accurately, it would be “field of unshareable class” but I’d mostly like to make it clear that the thing you are marking is a field.
2) “This class has not been configured for sharing (and must be added to the boot-jar). “ Why is the 2nd half of this sentence in parentheses?
3) In all of these cases, it would be most useful to know the particular field that cannot be shared and (if applicable) the particular class that cannot be shared and (if applicable) the path from the field to that class. It’s not clear to me that this information actually comes out in the errors above (in particular the path from field to non-portable class).
Fiona OShea 2008-12-17
Igal, assigning to you to add the error message to the Jira
ilevy 2009-01-19
The text for this error – or texts, to be more accurate – is complicated only because it’s being put together in code. Separate and external texts should be created for each flavor of this error, each given a unique ID, and then code can refer to the ID. Making the text independent of code will make it a lot easier to maintain.
ilevy 2009-01-19
Here’s the refactored NPOE message (shown with example values are shown for Referring class, Thread, JVM ID, and Non-portable class):
CLASS_NOT_ADAPTABLE, SUPER_CLASS_NOT_ADAPTABLE, SUBCLASS_OF_LOGICALLY_MANAGED_CLASS This class (or one of its superclasses) cannot be shared.
Possible actions to take:
-> Refactor your code to avoid sharing the unshareable class.
-> Mark the field (whose type is unshareable) transient in the
CLASS_NOT_IN_BOOT_JAR This class has not been configured for sharing and must be added to the boot JAR.
Possible actions to take: -> If this class can be made portable, add it to the Terracotta boot JAR:
- Add this class to the
section in the Terracotta configuration file (tc-config.xml by default). - Recreate the boot JAR using the Terracotta make-boot-jar script.
-> If this class cannot be made portable, do one of the following:
* Refactor your code to avoid sharing this class.
* Mark the field (whose type is unshareable) transient in the
CLASS_NOT_INCLUDED_IN_CONFIG, SUPER_CLASS_NOT_INSTRUMENTED This class (or one of its superclasses) has not been configured for sharing.
Possible actions to take: -> If the non-portable class is part of your native code, add it to the Terracotta configuration file (tc-config.xml by default):
- Locate the
element. - Add the following snippet:
the.problem.class </instrumented-classes>
If an <instrumented-classes> element is already present,
add the new includes inside it.
-> If the non-portable class is part of a framework or other 3rd-party source, try to avoid adding it to the Terracotta configuration file. Instead, consider doing one of the following:
- Refactor your code to avoid sharing this class.
- Use a Terracotta Integration Module. For example, if the non-portable class listed below is net.sf.ehcache.CacheManager, use the EHCache TIM.
- Mark the field (whose type is unshareable) transient in the
section of the Terracotta configuration file (tc-config.xml by default): the.problem.class.TheField
Alex Miller 2009-01-20
Reopening to actually change the code.
Fiona OShea 2009-01-27
upgraded to P1, as we need to get these errors fixed asap.
Walter Harley 2009-01-29
http://jira.terracotta.org/jira/browse/DEV-2333 describes an additional use case, not covered by the above messages.
This is the case where a TC object in the boot jar is intentionally nonportable, as with java.util.HashMap$KeySetWrapper (a TC-provided class). At present the message says the class needs to be added to the boot jar, which is confusing because (a) it’s already there; (b) the user would have no idea where it comes from anyway, since it’s not actually in java.util.HashMap; and (c) adding it would not fix the problem.
the object graph dump in the log file might give some more clues