|
View:
New views
13 Messages
—
Rating Filter:
Alert me
|
|
|
Assert that all models are detached at the end of the request?Is there an easy way to assert that all models are detached at the end
of the request? It does not look so easy to check this as models do not have common base class where one could register them for a check... I often use an additional model in a component and store it as a member field; if I forgot to detach() this model in the onDetach() handler, I would have a "dangling" model. That caused me quite some trouble once and I want to avoid it in the future. Thanks, Kaspar --------------------------------------------------------------------- To unsubscribe, e-mail: users-unsubscribe@... For additional commands, e-mail: users-help@... |
|
|
Re: Assert that all models are detached at the end of the request?no, there is no easy way to "assert" that any model has been detached,
because they do not keep a flag. in 1.5 we will implement it so that all fields of a component that implement idetachable are detached in the end of request via reflection, so that should help somewhat. -igor On Thu, Aug 28, 2008 at 1:57 PM, Kaspar Fischer <fischerk@...> wrote: > Is there an easy way to assert that all models are detached at the end of > the > request? > > It does not look so easy to check this as models do not have common base > class > where one could register them for a check... > > I often use an additional model in a component and store it as a member > field; > if I forgot to detach() this model in the onDetach() handler, I would have a > "dangling" model. That caused me quite some trouble once and I want to avoid > it in the future. > > Thanks, > Kaspar > > --------------------------------------------------------------------- > To unsubscribe, e-mail: users-unsubscribe@... > For additional commands, e-mail: users-help@... > > --------------------------------------------------------------------- To unsubscribe, e-mail: users-unsubscribe@... For additional commands, e-mail: users-help@... |
|
|
Re: Assert that all models are detached at the end of the request?you could extend the serializerchecker to check for underached models.
We did something similar checking for non-transient Entity objects. Iirc the code is either on my blog or Eelco's blog. Martijn On 8/28/08, Igor Vaynberg <igor.vaynberg@...> wrote: > no, there is no easy way to "assert" that any model has been detached, > because they do not keep a flag. > > in 1.5 we will implement it so that all fields of a component that > implement idetachable are detached in the end of request via > reflection, so that should help somewhat. > > -igor > > On Thu, Aug 28, 2008 at 1:57 PM, Kaspar Fischer <fischerk@...> > wrote: >> Is there an easy way to assert that all models are detached at the end of >> the >> request? >> >> It does not look so easy to check this as models do not have common base >> class >> where one could register them for a check... >> >> I often use an additional model in a component and store it as a member >> field; >> if I forgot to detach() this model in the onDetach() handler, I would have >> a >> "dangling" model. That caused me quite some trouble once and I want to >> avoid >> it in the future. >> >> Thanks, >> Kaspar >> >> --------------------------------------------------------------------- >> To unsubscribe, e-mail: users-unsubscribe@... >> For additional commands, e-mail: users-help@... >> >> > > --------------------------------------------------------------------- > To unsubscribe, e-mail: users-unsubscribe@... > For additional commands, e-mail: users-help@... > > -- Become a Wicket expert, learn from the best: http://wicketinaction.com Apache Wicket 1.3.4 is released Get it now: http://www.apache.org/dyn/closer.cgi/wicket/1.3. --------------------------------------------------------------------- To unsubscribe, e-mail: users-unsubscribe@... For additional commands, e-mail: users-help@... |
|
|
Re: Assert that all models are detached at the end of the request?Matijn, thank you for your hint.
I searched on your blog, http://martijndashorst.com/blog/, and Eelco's, http://day-to-day-stuff.blogspot.com/, but must have searched for the wrong thing ("transient", "entity", "SerializableChecker")... Anyways, I'd like to do what you suggest, but have a few question: I guess I have to provide my own implementation of IObjectStreamFactory in order to force my subclass of SerializableChecker to run (in development mode). For this, do I subclass IObjectStreamFactory.DefaultObjectStreamFactory or WicketObjectStreamFactory? Where would I install this custom IObjectStreamFactory? As to SerializableChecker itself, I think my version simply has to look for models in private void check(Object obj) { if (obj == null) { return; } Class<?> cls = obj.getClass(); nameStack.add(simpleName); traceStack.add(new TraceSlot(obj, fieldDescription)); if (!(obj instanceof Serializable) && (!Proxy.isProxyClass(cls))) { throw new WicketNotSerializableException( toPrettyPrintedStack(obj.getClass().getName()), exception); } // NEW if (obj instanceof LoadableDetachableModel) { LoadableDetachableModel m = (LoadableDetachableModel)m; if (m.isAttached()) { throw new IllegalStateException("Model not detached!"); } } // ... Regards, Kaspar On 29.08.2008, at 08:20, Martijn Dashorst wrote: > you could extend the serializerchecker to check for underached models. > We did something similar checking for non-transient Entity objects. > Iirc the code is either on my blog or Eelco's blog. > > Martijn > > On 8/28/08, Igor Vaynberg <igor.vaynberg@...> wrote: >> no, there is no easy way to "assert" that any model has been >> detached, >> because they do not keep a flag. >> >> in 1.5 we will implement it so that all fields of a component that >> implement idetachable are detached in the end of request via >> reflection, so that should help somewhat. >> >> -igor >> >> On Thu, Aug 28, 2008 at 1:57 PM, Kaspar Fischer >> <fischerk@...> >> wrote: >>> Is there an easy way to assert that all models are detached at the >>> end of >>> the >>> request? >>> >>> It does not look so easy to check this as models do not have >>> common base >>> class >>> where one could register them for a check... >>> >>> I often use an additional model in a component and store it as a >>> member >>> field; >>> if I forgot to detach() this model in the onDetach() handler, I >>> would have >>> a >>> "dangling" model. That caused me quite some trouble once and I >>> want to >>> avoid >>> it in the future. >>> >>> Thanks, >>> Kaspar >>> >>> --------------------------------------------------------------------- >>> To unsubscribe, e-mail: users-unsubscribe@... >>> For additional commands, e-mail: users-help@... >>> >>> >> >> --------------------------------------------------------------------- >> To unsubscribe, e-mail: users-unsubscribe@... >> For additional commands, e-mail: users-help@... >> >> > > > -- > Become a Wicket expert, learn from the best: http://wicketinaction.com > Apache Wicket 1.3.4 is released > Get it now: http://www.apache.org/dyn/closer.cgi/wicket/1.3. > > --------------------------------------------------------------------- > To unsubscribe, e-mail: users-unsubscribe@... > For additional commands, e-mail: users-help@... > --------------------------------------------------------------------- To unsubscribe, e-mail: users-unsubscribe@... For additional commands, e-mail: users-help@... |
|
|
Re: Assert that all models are detached at the end of the request?We just do it in CustomRequestCycle#onEndRequest():
@Override protected void onEndRequest() { if (Application.get().isDevelopment()) { // controleer of er hibernate objecten in de pagina vastgehouden worden. // eerst de pagina die het request heeft beantwoord Page requestPage = getRequest().getPage(); testDetachedObjects(requestPage); // als de response een Page heeft, dan deze controleren op de aanwezigheid van // hibernate objecten. if (getRequestTarget() instanceof IPageRequestTarget) { Page responsePage = ((IPageRequestTarget) getRequestTarget()).getPage(); if (responsePage != requestPage) { testDetachedObjects(responsePage); } } } And: private void testDetachedObjects(final Page page) { if (page == null) { return; } try { NotSerializableException exception = new NotSerializableException(); EntityAndSerializableChecker checker = new EntityAndSerializableChecker(exception); checker.writeObject(page); } catch (Exception ex) { log.error("Couldn't test/serialize the Page: " + page + ", error: " + ex); } } -- Become a Wicket expert, learn from the best: http://wicketinaction.com Apache Wicket 1.3.4 is released Get it now: http://www.apache.org/dyn/closer.cgi/wicket/1.3. --------------------------------------------------------------------- To unsubscribe, e-mail: users-unsubscribe@... For additional commands, e-mail: users-help@... |
|
|
Re: Assert that all models are detached at the end of the request?and yes, your implementation of the check looks good.
Martijn -- Become a Wicket expert, learn from the best: http://wicketinaction.com Apache Wicket 1.3.4 is released Get it now: http://www.apache.org/dyn/closer.cgi/wicket/1.3. --------------------------------------------------------------------- To unsubscribe, e-mail: users-unsubscribe@... For additional commands, e-mail: users-help@... |
|
|
Re: Assert that all models are detached at the end of the request?Many, many thanks for this! Very much appreciated. - Kaspar
On 29.08.2008, at 15:15, Martijn Dashorst wrote: > We just do it in CustomRequestCycle#onEndRequest(): > > @Override > protected void onEndRequest() > { > if (Application.get().isDevelopment()) > { > // controleer of er hibernate objecten in de pagina vastgehouden > worden. > // eerst de pagina die het request heeft beantwoord > > Page requestPage = getRequest().getPage(); > testDetachedObjects(requestPage); > > // als de response een Page heeft, dan deze controleren op de > aanwezigheid van > // hibernate objecten. > if (getRequestTarget() instanceof IPageRequestTarget) > { > Page responsePage = ((IPageRequestTarget) > getRequestTarget()).getPage(); > > if (responsePage != requestPage) > { > testDetachedObjects(responsePage); > } > } > } > > > And: > > private void testDetachedObjects(final Page page) > { > if (page == null) > { > return; > } > > try > { > NotSerializableException exception = new > NotSerializableException(); > EntityAndSerializableChecker checker = new > EntityAndSerializableChecker(exception); > checker.writeObject(page); > } > catch (Exception ex) > { > log.error("Couldn't test/serialize the Page: " + page + ", error: > " + ex); > } > } > > -- > Become a Wicket expert, learn from the best: http://wicketinaction.com > Apache Wicket 1.3.4 is released > Get it now: http://www.apache.org/dyn/closer.cgi/wicket/1.3. > > --------------------------------------------------------------------- > To unsubscribe, e-mail: users-unsubscribe@... > For additional commands, e-mail: users-help@... > --------------------------------------------------------------------- To unsubscribe, e-mail: users-unsubscribe@... For additional commands, e-mail: users-help@... |
|
|
Re: Assert that all models are detached at the end of the request?Eelco is on http://chillenious.wordpress.com.
The link you mentioned http://day-to-day-stuff.blogspot.com/ is from your's truly. Regards, Erik. Kaspar Fischer wrote: > Matijn, thank you for your hint. > > I searched on your blog, http://martijndashorst.com/blog/, and Eelco's, > http://day-to-day-stuff.blogspot.com/, but must have searched for the > wrong > thing ("transient", "entity", "SerializableChecker")... > > -- Erik van Oosten http://day-to-day-stuff.blogspot.com/ --------------------------------------------------------------------- To unsubscribe, e-mail: users-unsubscribe@... For additional commands, e-mail: users-help@... |
|
|
Re: Assert that all models are detached at the end of the request?For the sake of completeness, here is the solution I am currently
using. It uses, as suggested by Martijn, a custom request cycle and a modified version of SerializableChecker. You have to install the custom request cycle in your application using @Override public RequestCycle newRequestCycle(Request request, Response response) { return new CustomRequestCycle(this, (WebRequest) request, (WebResponse) response); } Hope this helps others, too! Kaspar // ***** FILE: CustomRequestCycle.java ***** import java.io.NotSerializableException; import org.apache.wicket.Page; import org.apache.wicket.Response; import org.apache.wicket.protocol.http.WebApplication; import org.apache.wicket.protocol.http.WebRequest; import org.apache.wicket.protocol.http.WebRequestCycle; import org.apache.wicket.request.target.component.IPageRequestTarget; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * A custom request cycle that checks, when in development mode, that all models of a page are * detached. Currently, only model that are instances of LoadableDetachableModel (including * subclasses) are checked. */ public class CustomRequestCycle extends WebRequestCycle { /** Logging object */ private static final Logger log = LoggerFactory.getLogger(WebRequestCycle.class); public CustomRequestCycle(WebApplication application, WebRequest request, Response response) { super(application, request, response); } @Override protected void onEndRequest() { super.onEndRequest(); if (WebApplication .DEVELOPMENT .equalsIgnoreCase(WebApplication.get().getConfigurationType())) { Page requestPage = getRequest().getPage(); testDetachedObjects(requestPage); if (getRequestTarget() instanceof IPageRequestTarget) { Page responsePage = ((IPageRequestTarget) getRequestTarget()).getPage(); if (responsePage != requestPage) { testDetachedObjects(responsePage); } } } } private void testDetachedObjects(final Page page) { if (page == null) { return; } try { NotSerializableException exception = new NotSerializableException( "Model is not detached when attempting to serialize!"); DetachedChecker checker = new DetachedChecker(exception); checker.writeObject(page); } catch (Exception ex) { log.error("Couldn't test/serialize the Page: " + page + ", error: " + ex); } } } // ***** FILE: DetachedChecker.java ***** import java.io.Externalizable; import java.io.IOException; import java.io.NotSerializableException; import java.io.ObjectOutput; import java.io.ObjectOutputStream; import java.io.ObjectStreamClass; import java.io.ObjectStreamField; import java.io.OutputStream; import java.io.Serializable; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import java.util.Date; import java.util.IdentityHashMap; import java.util.Iterator; import java.util.LinkedList; import java.util.Map; import org.apache.wicket.Component; import org.apache.wicket.WicketRuntimeException; import org.apache.wicket.model.LoadableDetachableModel; import org.apache.wicket.util.lang.Generics; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * This is taken from Wicket SerializableChecker.java (SVN r687197) and customized slightly * (see comments containing "KF"). See the latter file for all details, including terms of * use. Notice that this does not replace SerializableChecker; the latter is still run. */ public final class DetachedChecker extends ObjectOutputStream { /** * Exception that is thrown when a non-serializable object was found. */ public static final class WicketNotSerializableException extends WicketRuntimeException { private static final long serialVersionUID = 1L; WicketNotSerializableException(String message, Throwable cause) { super(message, cause); } } /** * Does absolutely nothing. */ private static class NoopOutputStream extends OutputStream { @Override public void close() { } @Override public void flush() { } @Override public void write(byte[] b) { } @Override public void write(byte[] b, int i, int l) { } @Override public void write(int b) { } } private static abstract class ObjectOutputAdaptor implements ObjectOutput { public void close() throws IOException { } public void flush() throws IOException { } public void write(byte[] b) throws IOException { } public void write(byte[] b, int off, int len) throws IOException { } public void write(int b) throws IOException { } public void writeBoolean(boolean v) throws IOException { } public void writeByte(int v) throws IOException { } public void writeBytes(String s) throws IOException { } public void writeChar(int v) throws IOException { } public void writeChars(String s) throws IOException { } public void writeDouble(double v) throws IOException { } public void writeFloat(float v) throws IOException { } public void writeInt(int v) throws IOException { } public void writeLong(long v) throws IOException { } public void writeShort(int v) throws IOException { } public void writeUTF(String str) throws IOException { } } /** Holds information about the field and the resulting object being traced. */ private static final class TraceSlot { private final String fieldDescription; private final Object object; TraceSlot(Object object, String fieldDescription) { super(); this.object = object; this.fieldDescription = fieldDescription; } @Override public String toString() { return object.getClass() + " - " + fieldDescription; } } private static final NoopOutputStream DUMMY_OUTPUT_STREAM = new NoopOutputStream(); /** log. */ private static final Logger log = LoggerFactory.getLogger(DetachedChecker.class); /** Whether we can execute the tests. If false, check will just return. */ private static boolean available = true; // this hack - accessing the serialization API through introspection - is // the only way to use Java serialization for our purposes without writing // the whole thing from scratch (and even then, it would be limited). This // way of working is of course fragile for internal API changes, but as we // do an extra check on availability and we report when we can't use this // introspection fu, we'll find out soon enough and clients on this class // can fall back on Java's default exception for serialization errors (which // sucks and is the main reason for this attempt). private static final Method LOOKUP_METHOD; private static final Method GET_CLASS_DATA_LAYOUT_METHOD; private static final Method GET_NUM_OBJ_FIELDS_METHOD; private static final Method GET_OBJ_FIELD_VALUES_METHOD; private static final Method GET_FIELD_METHOD; private static final Method HAS_WRITE_REPLACE_METHOD_METHOD; private static final Method INVOKE_WRITE_REPLACE_METHOD; static { try { LOOKUP_METHOD = ObjectStreamClass.class.getDeclaredMethod("lookup", new Class[] { Class.class, Boolean.TYPE }); LOOKUP_METHOD.setAccessible(true); GET_CLASS_DATA_LAYOUT_METHOD = ObjectStreamClass.class.getDeclaredMethod("getClassDataLayout", (Class[]) null); GET_CLASS_DATA_LAYOUT_METHOD.setAccessible(true); GET_NUM_OBJ_FIELDS_METHOD = ObjectStreamClass.class.getDeclaredMethod("getNumObjFields", (Class[]) null); GET_NUM_OBJ_FIELDS_METHOD.setAccessible(true); GET_OBJ_FIELD_VALUES_METHOD = ObjectStreamClass.class.getDeclaredMethod("getObjFieldValues", new Class[] { Object.class, Object[].class }); GET_OBJ_FIELD_VALUES_METHOD.setAccessible(true); GET_FIELD_METHOD = ObjectStreamField.class.getDeclaredMethod("getField", (Class[]) null); GET_FIELD_METHOD.setAccessible(true); HAS_WRITE_REPLACE_METHOD_METHOD = ObjectStreamClass.class.getDeclaredMethod("hasWriteReplaceMethod", (Class[]) null); HAS_WRITE_REPLACE_METHOD_METHOD.setAccessible(true); INVOKE_WRITE_REPLACE_METHOD = ObjectStreamClass.class.getDeclaredMethod("invokeWriteReplace", new Class[] { Object.class }); INVOKE_WRITE_REPLACE_METHOD.setAccessible(true); } catch (SecurityException e) { available = false; throw new RuntimeException(e); } catch (NoSuchMethodException e) { available = false; throw new RuntimeException(e); } } /** * Gets whether we can execute the tests. If false, calling {@link #check(Object)} will just * return and you are advised to rely on the {@link NotSerializableException}. Clients are * advised to call this method prior to calling the check method. * * @return whether security settings and underlying API etc allow for accessing the serialization * API using introspection */ public static boolean isAvailable() { return available; } /** object stack that with the trace path. */ private final LinkedList<TraceSlot> traceStack = new LinkedList<TraceSlot>(); /** set for checking circular references. */ private final Map<Object, Object> checked = new IdentityHashMap<Object, Object>(); /** string stack with current names pushed. */ private final LinkedList<String> nameStack = new LinkedList<String>(); /** root object being analyzed. */ private Object root; /** cache for classes - writeObject methods. */ private final Map<Class<?>, Object> writeObjectMethodCache = Generics.newHashMap(); /** current simple field name. */ private String simpleName = ""; /** current full field description. */ private String fieldDescription; /** Exception that should be set as the cause when throwing a new exception. */ private final NotSerializableException exception; /** * Construct. * * @param exception * exception that should be set as the cause when throwing a new exception * * @throws IOException */ public DetachedChecker(NotSerializableException exception) throws IOException { this.exception = exception; } /** * @see java.io.ObjectOutputStream#reset() */ @Override public void reset() throws IOException { root = null; checked.clear(); fieldDescription = null; simpleName = null; traceStack.clear(); nameStack.clear(); writeObjectMethodCache.clear(); } private void check(Object obj) { if (obj == null) { return; } Class<?> cls = obj.getClass(); nameStack.add(simpleName); traceStack.add(new TraceSlot(obj, fieldDescription)); if (!(obj instanceof Serializable) && (!Proxy.isProxyClass(cls))) { throw new WicketNotSerializableException (toPrettyPrintedStack(obj.getClass().getName()), exception); } // BEGIN KF if (obj instanceof LoadableDetachableModel) { LoadableDetachableModel model = (LoadableDetachableModel) obj; if (model.isAttached()) { Object value = model.getObject(); throw new WicketNotSerializableException (toPrettyPrintedStack(obj.getClass().getName()) + "\nmodel object: " + value, exception); } } // END KF ObjectStreamClass desc; for (;;) { try { desc = (ObjectStreamClass) LOOKUP_METHOD.invoke(null, new Object[] { cls, Boolean.TRUE }); Class<?> repCl; if (!((Boolean) HAS_WRITE_REPLACE_METHOD_METHOD.invoke(desc, (Object[]) null)).booleanValue() || (obj = INVOKE_WRITE_REPLACE_METHOD.invoke(desc, new Object[] { obj })) == null || (repCl = obj.getClass()) == cls) { break; } cls = repCl; } catch (IllegalAccessException e) { throw new RuntimeException(e); } catch (InvocationTargetException e) { throw new RuntimeException(e); } } if (cls.isPrimitive()) { // skip } else if (cls.isArray()) { checked.put(obj, null); Class<?> ccl = cls.getComponentType(); if (!(ccl.isPrimitive())) { Object[] objs = (Object[]) obj; for (int i = 0; i < objs.length; i++) { String arrayPos = "[" + i + "]"; simpleName = arrayPos; fieldDescription += arrayPos; check(objs[i]); } } } else if (obj instanceof Externalizable && (! Proxy.isProxyClass(cls))) { Externalizable extObj = (Externalizable) obj; try { extObj.writeExternal(new ObjectOutputAdaptor() { private int count = 0; public void writeObject(Object streamObj) throws IOException { // Check for circular reference. if (checked.containsKey(streamObj)) { return; } checked.put(streamObj, null); String arrayPos = "[write:" + count++ + "]"; simpleName = arrayPos; fieldDescription += arrayPos; check(streamObj); } }); } catch (Exception e) { if (e instanceof WicketNotSerializableException) { throw (WicketNotSerializableException) e; } log.warn("error delegating to Externalizable : " + e.getMessage() + ", path: " + currentPath()); } } else { Method writeObjectMethod = null; Object o = writeObjectMethodCache.get(cls); if (o != null) { if (o instanceof Method) { writeObjectMethod = (Method) o; } } else { try { writeObjectMethod = cls.getDeclaredMethod("writeObject", new Class[] { java.io.ObjectOutputStream.class }); } catch (SecurityException e) { // we can't access/ set accessible to true writeObjectMethodCache.put(cls, Boolean.FALSE); } catch (NoSuchMethodException e) { // cls doesn't have that method writeObjectMethodCache.put(cls, Boolean.FALSE); } } final Object original = obj; if (writeObjectMethod != null) { class InterceptingObjectOutputStream extends ObjectOutputStream { private int counter; InterceptingObjectOutputStream() throws IOException { super(DUMMY_OUTPUT_STREAM); enableReplaceObject(true); } @Override protected Object replaceObject(Object streamObj) throws IOException { if (streamObj == original) { return streamObj; } counter++; // Check for circular reference. if (checked.containsKey(streamObj)) { return null; } checked.put(original, null); String arrayPos = "[write:" + counter + "]"; simpleName = arrayPos; fieldDescription += arrayPos; check(streamObj); return streamObj; } } try { InterceptingObjectOutputStream ioos = new InterceptingObjectOutputStream(); ioos.writeObject(obj); } catch (Exception e) { if (e instanceof WicketNotSerializableException) { throw (WicketNotSerializableException) e; } log.warn("error delegating to writeObject : " + e.getMessage() + ", path: " + currentPath()); } } else { Object[] slots; try { slots = (Object[]) GET_CLASS_DATA_LAYOUT_METHOD.invoke(desc, (Object[]) null); } catch (Exception e) { throw new RuntimeException(e); } for (int i = 0; i < slots.length; i++) { ObjectStreamClass slotDesc; try { Field descField = slots[i].getClass().getDeclaredField("desc"); descField.setAccessible(true); slotDesc = (ObjectStreamClass) descField.get(slots[i]); } catch (Exception e) { throw new RuntimeException(e); } checked.put(obj, null); checkFields(obj, slotDesc); } } } traceStack.removeLast(); nameStack.removeLast(); } private void checkFields(Object obj, ObjectStreamClass desc) { int numFields; try { numFields = ((Integer) GET_NUM_OBJ_FIELDS_METHOD.invoke(desc, (Object[]) null)).intValue(); } catch (IllegalAccessException e) { throw new RuntimeException(e); } catch (InvocationTargetException e) { throw new RuntimeException(e); } if (numFields > 0) { int numPrimFields; ObjectStreamField[] fields = desc.getFields(); Object[] objVals = new Object[numFields]; numPrimFields = fields.length - objVals.length; try { GET_OBJ_FIELD_VALUES_METHOD.invoke(desc, new Object[] { obj, objVals }); } catch (IllegalAccessException e) { throw new RuntimeException(e); } catch (InvocationTargetException e) { throw new RuntimeException(e); } for (int i = 0; i < objVals.length; i++) { if (objVals[i] instanceof String || objVals[i] instanceof Number || objVals[i] instanceof Date || objVals[i] instanceof Boolean || objVals[i] instanceof Class) { // filter out common cases continue; } // Check for circular reference. if (checked.containsKey(objVals[i])) { continue; } ObjectStreamField fieldDesc = fields[numPrimFields + i]; Field field; try { field = (Field) GET_FIELD_METHOD.invoke(fieldDesc, (Object[]) null); } catch (IllegalAccessException e) { throw new RuntimeException(e); } catch (InvocationTargetException e) { throw new RuntimeException(e); } String fieldName = field.getName(); simpleName = field.getName(); fieldDescription = field.toString(); check(objVals[i]); } } } /** * @return name from root to current node concatenated with slashes */ private StringBuffer currentPath() { StringBuffer b = new StringBuffer(); for (Iterator<String> it = nameStack.iterator(); it.hasNext();) { b.append(it.next()); if (it.hasNext()) { b.append('/'); } } return b; } /** * Dump with indentation. * * @param type * the type that couldn't be serialized * @return A very pretty dump */ private final String toPrettyPrintedStack(String type) { StringBuffer result = new StringBuffer(); StringBuffer spaces = new StringBuffer(); result.append("Unable to serialize class: "); result.append(type); result.append("\nField hierarchy is:"); for (Iterator<TraceSlot> i = traceStack.listIterator(); i.hasNext();) { spaces.append(" "); TraceSlot slot = i.next(); result.append("\n").append(spaces).append(slot.fieldDescription); result.append(" [class=").append(slot.object.getClass().getName()); if (slot.object instanceof Component) { Component component = (Component) slot.object; result.append(", path=").append(component.getPath()); } result.append("]"); result.append(" {object:" + slot.object + "}"); } result.append(" <----- model that is not detached"); // KF return result.toString(); } /** * @see java.io.ObjectOutputStream#writeObjectOverride(java.lang.Object) */ @Override protected final void writeObjectOverride(Object obj) throws IOException { if (!available) { return; } root = obj; if (fieldDescription == null) { fieldDescription = (root instanceof Component) ? ((Component) root).getPath() : ""; } check(root); } } --------------------------------------------------------------------- To unsubscribe, e-mail: users-unsubscribe@... For additional commands, e-mail: users-help@... |
|
|
Re: Assert that all models are detached at the end of the request?Could you perhaps use an aspect for this?
On Thu, Aug 28, 2008 at 4:57 PM, Kaspar Fischer <fischerk@...> wrote: > Is there an easy way to assert that all models are detached at the end of > the > request? > > It does not look so easy to check this as models do not have common base > class > where one could register them for a check... > > I often use an additional model in a component and store it as a member > field; > if I forgot to detach() this model in the onDetach() handler, I would have a > "dangling" model. That caused me quite some trouble once and I want to avoid > it in the future. > > Thanks, > Kaspar > > --------------------------------------------------------------------- > To unsubscribe, e-mail: users-unsubscribe@... > For additional commands, e-mail: users-help@... > > --------------------------------------------------------------------- To unsubscribe, e-mail: users-unsubscribe@... For additional commands, e-mail: users-help@... |
|
|
Re: Assert that all models are detached at the end of the request?Why do you throw WicketNotSerializableException when the model is still
detached? On Fri, Sep 5, 2008 at 11:11 AM, Kaspar Fischer <fischerk@...>wrote: > For the sake of completeness, here is the solution I am currently using. It > uses, > as suggested by Martijn, a custom request cycle and a modified version of > SerializableChecker. You have to install the custom request cycle in your > application > using > > @Override > public RequestCycle newRequestCycle(Request request, Response response) > { > return new CustomRequestCycle(this, (WebRequest) request, (WebResponse) > response); > } > > Hope this helps others, too! > Kaspar > > // ***** FILE: CustomRequestCycle.java ***** > import java.io.NotSerializableException; > > import org.apache.wicket.Page; > import org.apache.wicket.Response; > import org.apache.wicket.protocol.http.WebApplication; > import org.apache.wicket.protocol.http.WebRequest; > import org.apache.wicket.protocol.http.WebRequestCycle; > import org.apache.wicket.request.target.component.IPageRequestTarget; > import org.slf4j.Logger; > import org.slf4j.LoggerFactory; > > /** > * A custom request cycle that checks, when in development mode, that all > models of a page are > * detached. Currently, only model that are instances of > LoadableDetachableModel (including > * subclasses) are checked. > */ > public class CustomRequestCycle extends WebRequestCycle > { > /** Logging object */ > private static final Logger log = > LoggerFactory.getLogger(WebRequestCycle.class); > > public CustomRequestCycle(WebApplication application, WebRequest request, > Response response) > { > super(application, request, response); > } > > @Override > protected void onEndRequest() > { > super.onEndRequest(); > > if > (WebApplication.DEVELOPMENT.equalsIgnoreCase(WebApplication.get().getConfigurationType())) > { > Page requestPage = getRequest().getPage(); > testDetachedObjects(requestPage); > > if (getRequestTarget() instanceof IPageRequestTarget) > { > Page responsePage = ((IPageRequestTarget) > getRequestTarget()).getPage(); > > if (responsePage != requestPage) > { > testDetachedObjects(responsePage); > } > } > } > } > > private void testDetachedObjects(final Page page) > { > if (page == null) > { > return; > } > > try > { > NotSerializableException exception = new NotSerializableException( > "Model is not detached when attempting to serialize!"); > DetachedChecker checker = new DetachedChecker(exception); > checker.writeObject(page); > } > catch (Exception ex) > { > log.error("Couldn't test/serialize the Page: " + page + ", error: " + > ex); > } > } > } > > > // |