We are co-developing a GWT web app that already has working RPC calls for other modules. We built a new RPC module (based on the existing architecture) that compiles and runs, but fails throwing a run-time exception on the following line:
this.dashboardService = GWT.create(DashboardService.class);
The last line in the console is "Uncaught exception escaped" followed by the stack trace to the GWT.create() line above, which is preceded by the console error message:
Deferred binding failed for ... expect subsequent failures [ERROR]
Before those two lines is a laundry list of red errors that begins as follows:
[INFO] [(...)] - Module ... has been loaded
[DEBUG] [(...)] - Rebinding (...).DashboardService
[DEBUG] [(...)] - Invoking generator com.google.gwt.user.rebind.rpc.ServiceInterfaceProxyGenerator
[DEBUG] [(...)] - Generating client proxy for remote service interface '(...).DashboardService'
[INFO] [(...)] - Checking type argument 0 of type 'java.util.Arrays.ArrayList' because it is exposed as an array with a maximum dimension of 1 in this type or one of its subtypes (reached via (...).DashboardChannelSummary)
.
.
.
(more errors without stack trace or line numbers)
The console asks "Did you forget to inherit a module?" but based upon my research, this is not the problem; the problem is somewhere in the GWT deferred binding process, which is not visible in the stack trace. I suspect the bolded line above to be the issue but I cannot make heads or tales of this error message without a line number. Here is the code with proprietary package /module names replaced with (...):
web.xml
<servlet>
<servlet-name>(...) DashboardService
</servlet-name>
<servlet-class>(...).server.DashboardServiceImpl
</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>(...) DashboardService
</servlet-name>
<url-pattern>/(...)/DashboardService</url-pattern>
</servlet-mapping>
DashboardChannelSummary.java
/**
* This class is an in memory representation of the results of a document search
*/
public class DashboardChannelSummary implements IsSerializable {
/** Only searches for documents from the past in this amount (the past week) */
private static final int DEFAULT_DASHBOARD_HISTORY_IN_DAYS = -7;
/** array of channels */
private List<Channel> channels;
/** iterator */
private Iterator<Channel> iterator;
/** */
private final static String IMAGE_PATH = "/images/channels/";
/** */
private final static String IMAGE_EXT = ".png";
/** constant for the channel header name */
public final static String BUSINESS_LABEL = "business aviation";
/** constant for the channel header name */
public final static String COMMERCIAL_LABEL = "commercial aviation";
/** constant for the channel header name */
public final static String MRO_LABEL = "mro";
/** constant for the channel header name */
public final static String DEFENSE_LABEL = "defense";
/**
*
*/
public enum CHANNEL_NAME {
BUSINESS (BUSINESS_LABEL, DocumentSummary.BA_ID),
COMMERCIAL (COMMERCIAL_LABEL, DocumentSummary.CA_ID),
MRO (MRO_LABEL, DocumentSummary.MRO_ID),
DEFENSE (DEFENSE_LABEL, DocumentSummary.DEFENSE_ID);
/** */
public String label;
/** */
public int ID;
/** */
private CHANNEL_NAME(String label, int ID) {
this.label = label.toUpperCase();
this.ID = ID;
}
};
/**
*
*/
public static List<String> channelNames() {
ArrayList<String> channels = new ArrayList<String>(CHANNEL_NAME.values().length);
for(int i=0; i<channels.size(); i++) {
channels.add(CHANNEL_NAME.values()[i].label);
}
return channels;
}
/**
*
*/
public static int[] channelIDs() {
int[] IDs = new int[CHANNEL_NAME.values().length];
for(int i=0; i<IDs.length; i++) {
IDs[i] = CHANNEL_NAME.values()[i].ID;
}
return IDs;
}
/**
*
* #return
*/
public static int channelCount() {
return CHANNEL_NAME.values().length;
}
/**
*
*/
public static Date cutoffDate() {
Date date = new Date(0);
CalendarUtil.addDaysToDate(date, DEFAULT_DASHBOARD_HISTORY_IN_DAYS);
return date;
}
/**
*
*/
public class Channel {
/** the name of this channel */
private CHANNEL_NAME name;
/** The list of documents */
private List<DocumentSummary> docs;
/** the iterator */
private Iterator<DocumentSummary> iterator;
/**
*
*/
public Channel(List<DocumentSummary> docs, CHANNEL_NAME name) {
this.docs = docs;
this.name = name;
iterator = docs.iterator();
}
/**
*
*/
public String getLabel() {
return name.label;
}
/**
*
*/
public List<DocumentSummary> getDocuments() {
return docs;
}
/**
*
*/
public boolean hasDocuments() {
return iterator.hasNext();
}
/**
*
* #return
*/
public DocumentSummary nextDocument() {
if(iterator.hasNext()) {
return iterator.next();
}
else {
return null;
}
}
/**
*
*/
public String nextImageURL() {
return GWT.getHostPageBaseURL().concat(IMAGE_PATH + String.valueOf(Random.nextInt(channels.size()) - 1) + IMAGE_EXT);
}
}
/**
* Constructor
*/
public DashboardChannelSummary() {
channels = new ArrayList<Channel>(CHANNEL_NAME.values().length);
iterator = channels.iterator();
}
/**
* Constructor
*/
public DashboardChannelSummary(List<List<DocumentSummary>> channelList) {
channels = new ArrayList<Channel>(CHANNEL_NAME.values().length);
iterator = channels.iterator();
int count = 0;
for(List<DocumentSummary> channelData : channelList)
{
channels.add(new Channel(channelData, CHANNEL_NAME.values()[count++]));
}
}
/**
* #return
*/
public List<Channel> getChannels() {
return channels;
}
/**
* #return
*/
public Channel getChannel(int channel) {
return channels.get(channel);
}
/**
* #return
*/
public Channel nextChannel() {
if(iterator.hasNext()) {
return iterator.next();
}
else {
return null;
}
}
/**
* #return
*/
public List<DocumentSummary> getDocuments(int channel) {
return this.getChannel(channel).getDocuments();
}
}
DashboardPresenter.java:
private final DashboardServiceAsync dashboardService;
and the deferred binding that fails in the Constructor:
this.dashboardService = GWT.create(DashboardService.class);
DashboardServiceAsync.java:
public interface DashboardServiceAsync {
/**
*
* #param channelIDs
* #param startDate
* #param async
*/
void getChannelSummary(int[] channelIDs, Date startDate, AsyncCallback<DashboardChannelSummary> async);
}
DashboardService.java:
#RemoteServiceRelativePath("DashboardService") public interface DashboardService extends RemoteService {
/**
*
* #param channelIDs
* #param startDate
* #return
*/
DashboardChannelSummary getChannelSummary(int[] channelIDs, Date startDate);
}
On the server:
DashboardServiceImpl.java:
public class DashboardServiceImpl extends RemoteServiceServlet implements DashboardService {
/**
*
* #param channelIDs
* #param startDate
* #return
*/
#Override
public DashboardChannelSummary getChannelSummary(int[] channelIDs, Date startDate) {
return new DashboardDaoImpl().getChannelSummary(channelIDs, startDate);
}
}
We have double and triple checked our RPC code for accuracy based on the documentation and the suggestions on SO, such as making sure the method signatures are correct across all interfaces and implementations. Anything obviously wrong jumping out to anyone? Is there a way we can we debug this error with more detail?
UPDATE
DashboardChannelSummary.java redesigned for max efficiency in transporting the data from the server to the client, with all properties now "serializable:"
/**
* This class is an in memory representation of the results of a document search.
*/
public class DashboardChannelSummary implements IsSerializable {
/** Only searches for documents from the past in this amount (the past week) */
private static final int DEFAULT_DASHBOARD_HISTORY_IN_DAYS = -7;
/** array of channels */
private ArrayList<ArrayList<DocumentSummary>> channels;
/** */
private int channel = 0;
/** */
private int image = 0;
/** */
private int index = 0;
/** */
private int last = 0;
/** */
private final static String IMAGE_PATH = "images/channels/";
/** */
private final static String IMAGE_EXT = ".jpg";
/** constant for the channel header name */
public final static String BUSINESS_LABEL = "business";
/** constant for the channel header name */
public final static String COMMERCIAL_LABEL = "commercial";
/** constant for the channel header name */
public final static String MRO_LABEL = "mro";
/** constant for the channel header name */
public final static String DEFENSE_LABEL = "defense";
/**
*
*/
public enum CHANNEL_NAME {
BUSINESS (BUSINESS_LABEL, DocumentSummary.BA_ID, "bus"),
COMMERCIAL (COMMERCIAL_LABEL, DocumentSummary.CA_ID, "_com"),
MRO (MRO_LABEL, DocumentSummary.MRO_ID, "mro"),
DEFENSE (DEFENSE_LABEL, DocumentSummary.DEFENSE_ID, "mil");
/** */
public String label;
/** */
public int ID;
/** */
public String prefix;
/** */
private CHANNEL_NAME(String label, int ID, String prefix) {
this.label = label.toUpperCase();
this.ID = ID;
this.prefix = prefix;
}
};
/**
*
*/
private String nextRandomImage() {
while(index == last) {
index = Random.nextInt(channels.size()) + 1;
}
last = index;
return String.valueOf(index);
}
/**
*
*/
public static List<String> channelNames() {
ArrayList<String> channels = new ArrayList<String>(CHANNEL_NAME.values().length);
for(int i=0; i<channels.size(); i++) {
channels.add(CHANNEL_NAME.values()[i].label);
}
return channels;
}
/**
*
*/
public static int[] channelIDs() {
int[] IDs = new int[CHANNEL_NAME.values().length];
for(int i=0; i<IDs.length; i++) {
IDs[i] = CHANNEL_NAME.values()[i].ID;
}
return IDs;
}
/**
*
* #return
*/
public static int channelCount() {
return CHANNEL_NAME.values().length;
}
/**
*
*/
public static Date cutoffDate() {
Date date = new Date();
CalendarUtil.addDaysToDate(date, DEFAULT_DASHBOARD_HISTORY_IN_DAYS);
return date;
}
/**
* Constructor
*/
public DashboardChannelSummary() {
}
/**
* Constructor
*/
public DashboardChannelSummary(ArrayList<ArrayList<DocumentSummary>> channels) {
this.channels = channels;
}
/**
*
*/
public String nextImageURL() {
if(++image > channels.get(channel - 1).size()) {
image = 0;
}
return GWT.getHostPageBaseURL() +
IMAGE_PATH +
CHANNEL_NAME.values()[channel - 1].prefix +
nextRandomImage() +
IMAGE_EXT;
}
/**
*
*/
public ArrayList<DocumentSummary> nextChannel() {
return channels.get(channel++);
}
/**
*
*/
public String toString() {
return this.getClass().toString() + " current channel : " + channel;
}
}
The culprit is most likely DashboardChannelSummary. To be sure, change the return type of getChannelSummary to something "safe", like String or just Void. If the error persists, there's an issue with the service's configuration (though, I doubt it would come up during GWT's compilation phase). If this service works, then you can be pretty sure that it's because DashboardChannelSummary is not serializable.
While the class itself has a no-args constructor and implements IsSerializable, not all the fields are serializable. You should have a closer look at the Channel class (maybe DocumentSummary too, but there's no code for it provided in the question) and the Iterator fields (ArrayList returns an Itr instance, which doesn't seem to be serializable).
If the error still persists, try simplifying DashboardChannelSummary until you get a working version and then work your way "up", until you find the part that is causing the error.
Related
I tried below avro schema :
{
"type": "record",
"name": "Tests",
"fields": [
{
"name": "name",
"alias": "first_name",
"type": "string",
"default": ""
}
]
}
when I "compile schema" this using avro tools I get the corresponding java file.
/**
* Autogenerated by Avro
*
* DO NOT EDIT DIRECTLY
*/
import org.apache.avro.generic.GenericArray;
import org.apache.avro.specific.SpecificData;
import org.apache.avro.util.Utf8;
import org.apache.avro.message.BinaryMessageEncoder;
import org.apache.avro.message.BinaryMessageDecoder;
import org.apache.avro.message.SchemaStore;
#org.apache.avro.specific.AvroGenerated
public class Tests extends org.apache.avro.specific.SpecificRecordBase implements org.apache.avro.specific.SpecificRecord {
private static final long serialVersionUID = 8259235364501890516L;
public static final org.apache.avro.Schema SCHEMA$ = new org.apache.avro.Schema.Parser().parse("{\"type\":\"record\",\"name\":\"Tests\",\"fields\":[{\"name\":\"name\",\"type\":\"string\",\"default\":\"\",\"alias\":\"first_name\"}]}");
public static org.apache.avro.Schema getClassSchema() { return SCHEMA$; }
private static SpecificData MODEL$ = new SpecificData();
private static final BinaryMessageEncoder<Tests> ENCODER =
new BinaryMessageEncoder<Tests>(MODEL$, SCHEMA$);
private static final BinaryMessageDecoder<Tests> DECODER =
new BinaryMessageDecoder<Tests>(MODEL$, SCHEMA$);
/**
* Return the BinaryMessageEncoder instance used by this class.
* #return the message encoder used by this class
*/
public static BinaryMessageEncoder<Tests> getEncoder() {
return ENCODER;
}
/**
* Return the BinaryMessageDecoder instance used by this class.
* #return the message decoder used by this class
*/
public static BinaryMessageDecoder<Tests> getDecoder() {
return DECODER;
}
/**
* Create a new BinaryMessageDecoder instance for this class that uses the specified {#link SchemaStore}.
* #param resolver a {#link SchemaStore} used to find schemas by fingerprint
* #return a BinaryMessageDecoder instance for this class backed by the given SchemaStore
*/
public static BinaryMessageDecoder<Tests> createDecoder(SchemaStore resolver) {
return new BinaryMessageDecoder<Tests>(MODEL$, SCHEMA$, resolver);
}
/**
* Serializes this Tests to a ByteBuffer.
* #return a buffer holding the serialized data for this instance
* #throws java.io.IOException if this instance could not be serialized
*/
public java.nio.ByteBuffer toByteBuffer() throws java.io.IOException {
return ENCODER.encode(this);
}
/**
* Deserializes a Tests from a ByteBuffer.
* #param b a byte buffer holding serialized data for an instance of this class
* #return a Tests instance decoded from the given buffer
* #throws java.io.IOException if the given bytes could not be deserialized into an instance of this class
*/
public static Tests fromByteBuffer(
java.nio.ByteBuffer b) throws java.io.IOException {
return DECODER.decode(b);
}
private java.lang.CharSequence name;
/**
* Default constructor. Note that this does not initialize fields
* to their default values from the schema. If that is desired then
* one should use <code>newBuilder()</code>.
*/
public Tests() {}
/**
* All-args constructor.
* #param name The new value for name
*/
public Tests(java.lang.CharSequence name) {
this.name = name;
}
public org.apache.avro.specific.SpecificData getSpecificData() { return MODEL$; }
public org.apache.avro.Schema getSchema() { return SCHEMA$; }
// Used by DatumWriter. Applications should not call.
public java.lang.Object get(int field$) {
switch (field$) {
case 0: return name;
default: throw new IndexOutOfBoundsException("Invalid index: " + field$);
}
}
// Used by DatumReader. Applications should not call.
#SuppressWarnings(value="unchecked")
public void put(int field$, java.lang.Object value$) {
switch (field$) {
case 0: name = (java.lang.CharSequence)value$; break;
default: throw new IndexOutOfBoundsException("Invalid index: " + field$);
}
}
/**
* Gets the value of the 'name' field.
* #return The value of the 'name' field.
*/
public java.lang.CharSequence getName() {
return name;
}
/**
* Sets the value of the 'name' field.
* #param value the value to set.
*/
public void setName(java.lang.CharSequence value) {
this.name = value;
}
/**
* Creates a new Tests RecordBuilder.
* #return A new Tests RecordBuilder
*/
public static Tests.Builder newBuilder() {
return new Tests.Builder();
}
/**
* Creates a new Tests RecordBuilder by copying an existing Builder.
* #param other The existing builder to copy.
* #return A new Tests RecordBuilder
*/
public static Tests.Builder newBuilder(Tests.Builder other) {
if (other == null) {
return new Tests.Builder();
} else {
return new Tests.Builder(other);
}
}
/**
* Creates a new Tests RecordBuilder by copying an existing Tests instance.
* #param other The existing instance to copy.
* #return A new Tests RecordBuilder
*/
public static Tests.Builder newBuilder(Tests other) {
if (other == null) {
return new Tests.Builder();
} else {
return new Tests.Builder(other);
}
}
/**
* RecordBuilder for Tests instances.
*/
#org.apache.avro.specific.AvroGenerated
public static class Builder extends org.apache.avro.specific.SpecificRecordBuilderBase<Tests>
implements org.apache.avro.data.RecordBuilder<Tests> {
private java.lang.CharSequence name;
/** Creates a new Builder */
private Builder() {
super(SCHEMA$);
}
/**
* Creates a Builder by copying an existing Builder.
* #param other The existing Builder to copy.
*/
private Builder(Tests.Builder other) {
super(other);
if (isValidValue(fields()[0], other.name)) {
this.name = data().deepCopy(fields()[0].schema(), other.name);
fieldSetFlags()[0] = other.fieldSetFlags()[0];
}
}
/**
* Creates a Builder by copying an existing Tests instance
* #param other The existing instance to copy.
*/
private Builder(Tests other) {
super(SCHEMA$);
if (isValidValue(fields()[0], other.name)) {
this.name = data().deepCopy(fields()[0].schema(), other.name);
fieldSetFlags()[0] = true;
}
}
/**
* Gets the value of the 'name' field.
* #return The value.
*/
public java.lang.CharSequence getName() {
return name;
}
/**
* Sets the value of the 'name' field.
* #param value The value of 'name'.
* #return This builder.
*/
public Tests.Builder setName(java.lang.CharSequence value) {
validate(fields()[0], value);
this.name = value;
fieldSetFlags()[0] = true;
return this;
}
/**
* Checks whether the 'name' field has been set.
* #return True if the 'name' field has been set, false otherwise.
*/
public boolean hasName() {
return fieldSetFlags()[0];
}
/**
* Clears the value of the 'name' field.
* #return This builder.
*/
public Tests.Builder clearName() {
name = null;
fieldSetFlags()[0] = false;
return this;
}
#Override
#SuppressWarnings("unchecked")
public Tests build() {
try {
Tests record = new Tests();
record.name = fieldSetFlags()[0] ? this.name : (java.lang.CharSequence) defaultValue(fields()[0]);
return record;
} catch (org.apache.avro.AvroMissingFieldException e) {
throw e;
} catch (java.lang.Exception e) {
throw new org.apache.avro.AvroRuntimeException(e);
}
}
}
#SuppressWarnings("unchecked")
private static final org.apache.avro.io.DatumWriter<Tests>
WRITER$ = (org.apache.avro.io.DatumWriter<Tests>)MODEL$.createDatumWriter(SCHEMA$);
#Override public void writeExternal(java.io.ObjectOutput out)
throws java.io.IOException {
WRITER$.write(this, SpecificData.getEncoder(out));
}
#SuppressWarnings("unchecked")
private static final org.apache.avro.io.DatumReader<Tests>
READER$ = (org.apache.avro.io.DatumReader<Tests>)MODEL$.createDatumReader(SCHEMA$);
#Override public void readExternal(java.io.ObjectInput in)
throws java.io.IOException {
READER$.read(this, SpecificData.getDecoder(in));
}
#Override protected boolean hasCustomCoders() { return true; }
#Override public void customEncode(org.apache.avro.io.Encoder out)
throws java.io.IOException
{
out.writeString(this.name);
}
#Override public void customDecode(org.apache.avro.io.ResolvingDecoder in)
throws java.io.IOException
{
org.apache.avro.Schema.Field[] fieldOrder = in.readFieldOrderIfDiff();
if (fieldOrder == null) {
this.name = in.readString(this.name instanceof Utf8 ? (Utf8)this.name : null);
} else {
for (int i = 0; i < 1; i++) {
switch (fieldOrder[i].pos()) {
case 0:
this.name = in.readString(this.name instanceof Utf8 ? (Utf8)this.name : null);
break;
default:
throw new java.io.IOException("Corrupt ResolvingDecoder.");
}
}
}
}
}
I am wondering where is the getter/setter for alias? How can i use it? I understand if I have avro record then I can use the alias but how to I generate Avro record using Java file using that alias?
aliases is responsible for providing an alternate name to a field. Documentation from Apache Avro.
If you update alias to aliases, this will work:
{
"type": "record",
"name": "Tests",
"fields": [
{
"name": "first_name",
"aliases": ["former_name_of_field"],
"type": "string",
"default": ""
}
]
}
This is an optional field to support schema evolution.
/**
* Autogenerated by Avro
*
* DO NOT EDIT DIRECTLY
*/
import org.apache.avro.generic.GenericArray;
import org.apache.avro.specific.SpecificData;
import org.apache.avro.util.Utf8;
import org.apache.avro.message.BinaryMessageEncoder;
import org.apache.avro.message.BinaryMessageDecoder;
import org.apache.avro.message.SchemaStore;
#org.apache.avro.specific.AvroGenerated
public class Tests extends org.apache.avro.specific.SpecificRecordBase implements org.apache.avro.specific.SpecificRecord {
private static final long serialVersionUID = -2440753220882419647L;
public static final org.apache.avro.Schema SCHEMA$ = new org.apache.avro.Schema.Parser().parse("{\"type\":\"record\",\"name\":\"Tests\",\"fields\":[{\"name\":\"first_name\",\"type\":{\"type\":\"string\",\"avro.java.string\":\"String\"},\"default\":\"\",\"aliases\":[\"former_name_of_field\"]}]}");
public static org.apache.avro.Schema getClassSchema() { return SCHEMA$; }
private static SpecificData MODEL$ = new SpecificData();
private static final BinaryMessageEncoder<Tests> ENCODER =
new BinaryMessageEncoder<Tests>(MODEL$, SCHEMA$);
private static final BinaryMessageDecoder<Tests> DECODER =
new BinaryMessageDecoder<Tests>(MODEL$, SCHEMA$);
/**
* Return the BinaryMessageEncoder instance used by this class.
* #return the message encoder used by this class
*/
public static BinaryMessageEncoder<Tests> getEncoder() {
return ENCODER;
}
/**
* Return the BinaryMessageDecoder instance used by this class.
* #return the message decoder used by this class
*/
public static BinaryMessageDecoder<Tests> getDecoder() {
return DECODER;
}
/**
* Create a new BinaryMessageDecoder instance for this class that uses the specified {#link SchemaStore}.
* #param resolver a {#link SchemaStore} used to find schemas by fingerprint
* #return a BinaryMessageDecoder instance for this class backed by the given SchemaStore
*/
public static BinaryMessageDecoder<Tests> createDecoder(SchemaStore resolver) {
return new BinaryMessageDecoder<Tests>(MODEL$, SCHEMA$, resolver);
}
/**
* Serializes this Tests to a ByteBuffer.
* #return a buffer holding the serialized data for this instance
* #throws java.io.IOException if this instance could not be serialized
*/
public java.nio.ByteBuffer toByteBuffer() throws java.io.IOException {
return ENCODER.encode(this);
}
/**
* Deserializes a Tests from a ByteBuffer.
* #param b a byte buffer holding serialized data for an instance of this class
* #return a Tests instance decoded from the given buffer
* #throws java.io.IOException if the given bytes could not be deserialized into an instance of this class
*/
public static Tests fromByteBuffer(
java.nio.ByteBuffer b) throws java.io.IOException {
return DECODER.decode(b);
}
#Deprecated public java.lang.String first_name;
/**
* Default constructor. Note that this does not initialize fields
* to their default values from the schema. If that is desired then
* one should use <code>newBuilder()</code>.
*/
public Tests() {}
/**
* All-args constructor.
* #param first_name The new value for first_name
*/
public Tests(java.lang.String first_name) {
this.first_name = first_name;
}
public org.apache.avro.specific.SpecificData getSpecificData() { return MODEL$; }
public org.apache.avro.Schema getSchema() { return SCHEMA$; }
// Used by DatumWriter. Applications should not call.
public java.lang.Object get(int field$) {
switch (field$) {
case 0: return first_name;
default: throw new IndexOutOfBoundsException("Invalid index: " + field$);
}
}
// Used by DatumReader. Applications should not call.
#SuppressWarnings(value="unchecked")
public void put(int field$, java.lang.Object value$) {
switch (field$) {
case 0: first_name = value$ != null ? value$.toString() : null; break;
default: throw new IndexOutOfBoundsException("Invalid index: " + field$);
}
}
/**
* Gets the value of the 'first_name' field.
* #return The value of the 'first_name' field.
*/
public java.lang.String getFirstName() {
return first_name;
}
/**
* Sets the value of the 'first_name' field.
* #param value the value to set.
*/
public void setFirstName(java.lang.String value) {
this.first_name = value;
}
/**
* Creates a new Tests RecordBuilder.
* #return A new Tests RecordBuilder
*/
public static Tests.Builder newBuilder() {
return new Tests.Builder();
}
/**
* Creates a new Tests RecordBuilder by copying an existing Builder.
* #param other The existing builder to copy.
* #return A new Tests RecordBuilder
*/
public static Tests.Builder newBuilder(Tests.Builder other) {
if (other == null) {
return new Tests.Builder();
} else {
return new Tests.Builder(other);
}
}
/**
* Creates a new Tests RecordBuilder by copying an existing Tests instance.
* #param other The existing instance to copy.
* #return A new Tests RecordBuilder
*/
public static Tests.Builder newBuilder(Tests other) {
if (other == null) {
return new Tests.Builder();
} else {
return new Tests.Builder(other);
}
}
/**
* RecordBuilder for Tests instances.
*/
#org.apache.avro.specific.AvroGenerated
public static class Builder extends org.apache.avro.specific.SpecificRecordBuilderBase<Tests>
implements org.apache.avro.data.RecordBuilder<Tests> {
private java.lang.String first_name;
/** Creates a new Builder */
private Builder() {
super(SCHEMA$);
}
/**
* Creates a Builder by copying an existing Builder.
* #param other The existing Builder to copy.
*/
private Builder(Tests.Builder other) {
super(other);
if (isValidValue(fields()[0], other.first_name)) {
this.first_name = data().deepCopy(fields()[0].schema(), other.first_name);
fieldSetFlags()[0] = other.fieldSetFlags()[0];
}
}
/**
* Creates a Builder by copying an existing Tests instance
* #param other The existing instance to copy.
*/
private Builder(Tests other) {
super(SCHEMA$);
if (isValidValue(fields()[0], other.first_name)) {
this.first_name = data().deepCopy(fields()[0].schema(), other.first_name);
fieldSetFlags()[0] = true;
}
}
/**
* Gets the value of the 'first_name' field.
* #return The value.
*/
public java.lang.String getFirstName() {
return first_name;
}
/**
* Sets the value of the 'first_name' field.
* #param value The value of 'first_name'.
* #return This builder.
*/
public Tests.Builder setFirstName(java.lang.String value) {
validate(fields()[0], value);
this.first_name = value;
fieldSetFlags()[0] = true;
return this;
}
/**
* Checks whether the 'first_name' field has been set.
* #return True if the 'first_name' field has been set, false otherwise.
*/
public boolean hasFirstName() {
return fieldSetFlags()[0];
}
/**
* Clears the value of the 'first_name' field.
* #return This builder.
*/
public Tests.Builder clearFirstName() {
first_name = null;
fieldSetFlags()[0] = false;
return this;
}
#Override
#SuppressWarnings("unchecked")
public Tests build() {
try {
Tests record = new Tests();
record.first_name = fieldSetFlags()[0] ? this.first_name : (java.lang.String) defaultValue(fields()[0]);
return record;
} catch (org.apache.avro.AvroMissingFieldException e) {
throw e;
} catch (java.lang.Exception e) {
throw new org.apache.avro.AvroRuntimeException(e);
}
}
}
#SuppressWarnings("unchecked")
private static final org.apache.avro.io.DatumWriter<Tests>
WRITER$ = (org.apache.avro.io.DatumWriter<Tests>)MODEL$.createDatumWriter(SCHEMA$);
#Override public void writeExternal(java.io.ObjectOutput out)
throws java.io.IOException {
WRITER$.write(this, SpecificData.getEncoder(out));
}
#SuppressWarnings("unchecked")
private static final org.apache.avro.io.DatumReader<Tests>
READER$ = (org.apache.avro.io.DatumReader<Tests>)MODEL$.createDatumReader(SCHEMA$);
#Override public void readExternal(java.io.ObjectInput in)
throws java.io.IOException {
READER$.read(this, SpecificData.getDecoder(in));
}
#Override protected boolean hasCustomCoders() { return true; }
#Override public void customEncode(org.apache.avro.io.Encoder out)
throws java.io.IOException
{
out.writeString(this.first_name);
}
#Override public void customDecode(org.apache.avro.io.ResolvingDecoder in)
throws java.io.IOException
{
org.apache.avro.Schema.Field[] fieldOrder = in.readFieldOrderIfDiff();
if (fieldOrder == null) {
this.first_name = in.readString();
} else {
for (int i = 0; i < 1; i++) {
switch (fieldOrder[i].pos()) {
case 0:
this.first_name = in.readString();
break;
default:
throw new java.io.IOException("Corrupt ResolvingDecoder.");
}
}
}
}
}
I do not believe it is possible to set aliases via Java code.
Here is my problem I can't seem to figure out how to invoke a ParkingTicket object if (carMinutesPaid>meterMinutesPaid)? can any one help here are the details below to the question.
public static ParkingTicket checkParking(int carMinutesParked, int meterMinutesPaid)
{
Car parker = carMinutesParked;
ParkingMeter parkee = parkee;
if(carMinutesParked>meterMinutesPaid){
return new ParkingTicket(parker, parkee);
}
else if(carMinutesParked<=meterMinutesPaid){
System.out.println("null");
}
return new ParkingTicket(parker, parkee);
}
Here is the question for my project.
Remember, this method must be able to be used without a ParkingTicket object in existence.
Using a Car parameter and a ParkingMeter parameter, decide whether a ParkingTicket object should be created.
Invoke ParkingTicket(parker, parkee) if a ticket was merited, and return the result.
Return null if a ticket was not merited.
Here is my car class:
/**
* This is a Car class for Impark.
*
* #author Tre
* #version 2.0 15 October 2015
*/
public class Car
{
private static final int MINIMUM_PLATE_LENGTH=2;
private static final int MAXIMUM_PLATE_LENGTH=7;
public static final char MANUAL_TRANSMISSION='m';
public static final char AUTOMATIC_TRANSMISSION='a';
private static int defaultMinutesParked = 0;
private static double defaultOdometerInKm = 50000.5;
private String licensePlate;
private char transmissionType;
private double odometerInKm;
private int minutesParked;
/**
* #param newProposedLicensePlate the license plate of the car can equal null
* but must be between MINIMUM_PLATE_LENGTH and MAXIMUM_PLATE_LENGTH
*/
public Car(String newProposedLicensePlate)
{
setLicensePlate(newProposedLicensePlate);
transmissionType = AUTOMATIC_TRANSMISSION;
odometerInKm = defaultOdometerInKm;
minutesParked = defaultMinutesParked;
}
/**
* #return the license plate of the car can equal null
* but must be between MINIMUM_PLATE_LENGTH and MAXIMUM_PLATE_LENGTH
*/
public String getLicensePlate()
{
return licensePlate;
}
/**
* #return the transmission type MANUAL_TRANSMISSION or AUTOMATIC_TRANSMISSION
*/
public char getTransmissionType()
{
return transmissionType;
}
/**
* #return the odometer in kilometers
*/
public double getOdometerInKm()
{
return odometerInKm;
}
/**
* Recieve the license plate
* Mutator.licensePlate.
* #param proposedLicense String Conforming to ICBC *length* guidlines:
* http://www.icbc.com/vehicle-registration/license-plates/Pages/Personalized-licence-plates.aspx
* May also be null. The null represents a car without a plate
* If validation fails, null will be set.
*/
public void setLicensePlate(String proposedLicense)
{
if(proposedLicense==null){
licensePlate = proposedLicense;
}
else if(proposedLicense.length()>=MINIMUM_PLATE_LENGTH && proposedLicense.length()<=MAXIMUM_PLATE_LENGTH){
licensePlate = proposedLicense;
}
else{
licensePlate = null;
}
}
/**
* #param mOrA recieve the transmission type MANUAL_TRANSMISSION or AUTOMATIC_TRANSMISSION
* if invalid type of transmission is entered then will return "Installation failure: 'mOrA' is not a vaild transmission type"
*/
public void setTransmissionType(char mOrA)
{
if(mOrA==MANUAL_TRANSMISSION){
transmissionType = mOrA;
}
else if(mOrA==AUTOMATIC_TRANSMISSION){
transmissionType = mOrA;
}
else if (mOrA==mOrA){
System.out.println("Installation failure:" + " " + ("'")+(mOrA)+("'") + " " + "is not a valid transmission type.");
}
else{
transmissionType = mOrA;
}
}
/**
* #return the value of the odometer in with the String kilometers
*/
public String readOdometer()
{
return odometerInKm + " " + "kilometers";
}
/**
* #return the false if the minutesParked equals zero; otherwise true
*/
public boolean isParked()
{
if(minutesParked==defaultMinutesParked){
return false;
}
else{
return true;
}
}
/**
* #param duration replaces any existing value in minutesParked with the value from duration
*/
public void park(int duration)
{
if(duration>=defaultMinutesParked){
minutesParked = duration;
}
}
/**
* #param aOdometerInKm recieve the odometer in kilometers
*/
public void setOdometerInKm(double aOdometerInKm)
{
odometerInKm = aOdometerInKm;
}
/**
* #param aMinutesParked recieve the minutes parked in the stall but can not be a negative number
* if invalid number of minutes is entered then the number of minutes will not change.
*/
public void setMinutesParked(int aMinutesParked)
{
if(aMinutesParked>=defaultMinutesParked){
minutesParked = aMinutesParked;
}
else{
return;
}
}
/**
* #return the minutes parked
*/
public int getMinutesParked()
{
return minutesParked;
}
}
here is my ParkingMeter class:
/**
* This is a ParkingMeter class for Impark.
*
* #author Tre
* #version 2.0 15 October 2015
*/
public class ParkingMeter
{
private int minutesPaid;
private String methodPaid;
/**
* #param newMinutesPaid the minutes paid for parking meter
*/
public ParkingMeter()
{
}
/**
* #return the minutes paid
*/
public int getMinutesPaid()
{
return minutesPaid;
}
/**
* #return the method paid
*/
public String getMethodPaid()
{
return methodPaid;
}
/**
* #param paidBy the payment method customer will paid by
*/
public void setMethodPaid(String paidBy) /* BONUS for creating method paid */
{
if(methodPaid=="Visa"){
methodPaid = paidBy;
}
else if(methodPaid=="Master Card"){
methodPaid = paidBy;
}
else if(methodPaid=="American Express"){
methodPaid = paidBy;
}
else if(methodPaid=="Cash"){
methodPaid = paidBy;
}
else if(methodPaid=="Debit"){
methodPaid = paidBy;
}
else{
methodPaid = paidBy;
}
}
/**
* #param quantity the added minutes paid must not have a negative number
*/
public void addMinutesPaid(int quantity)
{
if(quantity>=0){
minutesPaid+=quantity;
}
}
}
and here is my ParkingTicket class:
/**
* This is a ParkingTicket class for Impark.
*
* #author Tre
* #version 1.0
*/
public class ParkingTicket
{
private final String referenceNumber;
private static String carLicensePlate;
private static int carMinutesParked;
private static int meterMinutesPaid;
private static int count = 1000;
private static String PREFIX = "V";
/**
* #param recorededLicense the value of the tick number
*/
private ParkingTicket(String recordedLicense, int newCarMinutesParked, int newMeterPaidMinutes)
{
referenceNumber = (PREFIX+count++);
carMinutesParked = newCarMinutesParked;
meterMinutesPaid = newMeterPaidMinutes;
}
/**
* #param
*/
private ParkingTicket(Car parker, ParkingMeter parkee)
{
this(parker.getLicensePlate(), parker.getMinutesParked(), parkee.getMinutesPaid());
}
/**
* #return referenceNumber the reference number
*/
public String getReferenceNumber()
{
return referenceNumber;
}
/**
* #return carLicensePlate the car's license plate
*/
public String getCarLicensePlate()
{
return carLicensePlate;
}
/**
* #return carMinutesParked the minutes car was parked
*/
public int getCarMinutesParked()
{
return carMinutesParked;
}
/**
* #return meterMinutesPaid the minutes paid on meter
*/
public int getMeterMinutesPaid()
{
return meterMinutesPaid;
}
/**
* #return count the with initial value of 1000
*/
public int getCount()
{
return count;
}
public static ParkingTicket checkParking(int carMinutesParked, int meterMinutesPaid)
{
Car parker = carMinutesParked;
ParkingMeter parkee = parkee;
if(carMinutesParked>meterMinutesPaid){
return new ParkingTicket(parker, parkee);
}
else if(carMinutesParked<=meterMinutesPaid){
return null;
}
return new ParkingTicket(parker, parkee);
}
}
This requirement:
Using a Car parameter and a ParkingMeter parameter, decide whether a
ParkingTicket object should be created.
suggests that you provide two parameters to the checkParking method, one is of the type Car and one of the ParkingMeter. So it should be like so:
public static ParkingTicket checkParking(Car car, ParkingMeter meter)
This code :
Car parker = carMinutesParked;
ParkingMeter parkee = parkee;
won't even compile
line 1: you're trying to assign int to object - that's called type mismatch.
line 2: variable parkee is not declared anywhere (except for the headline of the question).
You see, only the Car object holds the information about the parking duration, and you need the object for creating parking ticket. Same for the ParkingMeter
It should be vice versa - you get the values from the objects:
int carMinutesParked = car.getMinutesParked();
int meterMinutesPaid = meter.getMinutesPaid();
and proceed from here with if( or even use it in if without declaring temporary variables).
This one:
Invoke ParkingTicket(parker, parkee) if a ticket was merited, and
return the result.
you did OK.
Now this requirement:
Return null if a ticket was not merited.
suggest the method will return null, not string that equals to "null" .
So, based on these requirements it should rather be:
public static ParkingTicket checkParking(Car car, ParkingMeter meter)
{
//sanity check (bonus)
if ((car == null) || (meter == null))
return null;
if(car.getMinutesParked() > meter.getMinutesPaid()){
return new ParkingTicket(car, meter);
}
return null;
}
Note however, I don't know if you need any additional logic in this code and don't suggest this should be your final version, just explaining the general approach.
I am getting this warning when using Gson to convert a JSON string to a Java object. Why am I getting it and how can I solve it?
This is the warning I getting in code:
Unchecked assignment:
'net.brawtasports.brawtasportsgps.model.JSONKeys' to
'net.brawtasports.brawtasportsgps.model.JSONKeys<net.brawtasports.brawtasportsgps.model.team.Object>'
This is the error I get at runtime:
java.lang.ClassCastException:
com.google.gson.internal.LinkedTreeMap cannot be cast to
net.brawtasports.brawtasportsgps.model.team.Object
And this is my code:
String jsonString = Preferences.readFromPreferences(ApplicationConstants.team_data,"");
Gson gson = new Gson();
JSONKeys<Object> teamMembers = gson.fromJson(jsonString, JSONKeys.class); //converts json string to java object
Object players = teamMembers.getObject();//object is my custom class
//ArrayAdapter<String> arrayAdapter = new ArrayAdapter<String>(getActivity(),android.R.layout.simple_spinner_dropdown_item,players);
ArrayAdapter arrayAdapter = new ArrayAdapter(getActivity(),android.R.layout.simple_spinner_dropdown_item,players.getPlayersSummary());
player1.setAdapter(arrayAdapter);
Here is the code for my JSONKeys POJO:
public class JSONKeys<T> {
private boolean Success;
private String Message;
private int ObjectIdentifier;
private T Object;
private java.util.List<List> List = new ArrayList<List>();
private int TotalRecords;
private String ErrorMessage;
private int Code;
private net.brawtasports.brawtasportsgps.model.match.Criteria Criteria;
private net.brawtasports.brawtasportsgps.model.match.SearchInfo SearchInfo;
//Add Object from match class
/**
* #return The Criteria
*/
public net.brawtasports.brawtasportsgps.model.match.Criteria getCriteria() {
return Criteria;
}
/**
* #param Criteria The Criteria
*/
public void setCriteria(net.brawtasports.brawtasportsgps.model.match.Criteria Criteria) {
this.Criteria = Criteria;
}
/**
* #return The SearchInfo
*/
public net.brawtasports.brawtasportsgps.model.match.SearchInfo getSearchInfo() {
return SearchInfo;
}
/**
* #param SearchInfo The SearchInfo
*/
public void setSearchInfo(net.brawtasports.brawtasportsgps.model.match.SearchInfo SearchInfo) {
this.SearchInfo = SearchInfo;
}
/**
* #return The List
*/
public java.util.List<List> getList() {
return List;
}
/**
* #param List The List
*/
public void setLArrayListList(java.util.List<List> List) {
this.List = List;
}
/**
* #return The Code
*/
public int getCode() {
return Code;
}
/**
* #param Code The Code
*/
public void setCode(int Code) {
this.Code = Code;
}
/**
* #return The TotalRecords
*/
public int getTotalRecords() {
return TotalRecords;
}
/**
* #param TotalRecords The TotalRecords
*/
public void setTotalRecords(int TotalRecords) {
this.TotalRecords = TotalRecords;
}
/**
* #return The ErrorMessage
*/
public String getErrorMessage() {
return ErrorMessage;
}
/**
* #param ErrorMessage The ErrorMessage
*/
public void setErrorMessage(String ErrorMessage) {
this.ErrorMessage = ErrorMessage;
}
/**
*
* #return
* The message
*/
public String getMessage() {
return Message;
}
/**
*
* #param message
* The message
*/
public void setMessage(String message) {
this.Message = message;
}
/**
*
* #return
* The Success
*/
public boolean isSuccess() {
return Success;
}
/**
*
* #param Success
* The Success
*/
public void setSuccess(boolean Success) {
this.Success = Success;
}
/**
*
* #return
* The ObjectIdentifier
*/
public int getObjectIdentifier() {
return ObjectIdentifier;
}
/**
*
* #param ObjectIdentifier
* The ObjectIdentifier
*/
public void setObjectIdentifier(int ObjectIdentifier) {
this.ObjectIdentifier = ObjectIdentifier;
}
/**
*
* #return
* The Object
*/
public T getObject() {
return Object;
}
/**
*
* #param Object
* The Object
*/
public void setObject(T Object) {
this.Object = Object;
}
}
and for my Object POJO it is:
public class Object {
private HomeTeamGoals HomeTeamGoals;
private AwayTeamGoals AwayTeamGoals;
private List<PlayersSummary> PlayersSummary = new ArrayList<PlayersSummary>();
private TeamSummary TeamSummary;
/**
*
* #return
* The HomeTeamGoals
*/
public HomeTeamGoals getHomeTeamGoals() {
return HomeTeamGoals;
}
/**
*
* #param HomeTeamGoals
* The HomeTeamGoals
*/
public void setHomeTeamGoals(HomeTeamGoals HomeTeamGoals) {
this.HomeTeamGoals = HomeTeamGoals;
}
/**
*
* #return
* The AwayTeamGoals
*/
public AwayTeamGoals getAwayTeamGoals() {
return AwayTeamGoals;
}
/**
*
* #param AwayTeamGoals
* The AwayTeamGoals
*/
public void setAwayTeamGoals(AwayTeamGoals AwayTeamGoals) {
this.AwayTeamGoals = AwayTeamGoals;
}
/**
*
* #return
* The PlayersSummary
*/
public List<PlayersSummary> getPlayersSummary() {
return PlayersSummary;
}
/**
*
* #param PlayersSummary
* The PlayersSummary
*/
public void setPlayersSummary(List<PlayersSummary> PlayersSummary) {
this.PlayersSummary = PlayersSummary;
}
/**
*
* #return
* The TeamSummary
*/
public TeamSummary getTeamSummary() {
return TeamSummary;
}
/**
*
* #param TeamSummary
* The TeamSummary
*/
public void setTeamSummary(TeamSummary TeamSummary) {
this.TeamSummary = TeamSummary;
}
}
You need to use a fully specified type when deserializing generics. They key line that needs changing is here:
JSONKeys<Object> teamMembers = gson.fromJson(jsonString, JSONKeys.class);
Because you're using JSONKeys.class, Gson doesn't know what the generic type of JSONKeys is. Instead, use this:
JSONKeys<Object> teamMembers = gson.fromJson(jsonString,
new TypeToken<JSONKeys<net.brawtasports.brawtasportsgps.model.team.Object>>(){}.getType());
This will tell Gson which generic type you need to use. See my explanation for why this works here: How does Gson TypeToken work?
As an aside, don't name your classes the same thing as anything in the java.lang package. It makes your code really confusing for people reading it and can cause unforseen bugs when you accidentally refer to the wrong one by forgetting an import statement.
I'm creating small javaEE Application I have problem with vendorsProdcut name dropdownbox is not showing name only array object like this see the images
Just want to ask how can I get the product name from arraylist to fix my problem?
just wondering is there are away to bring arraylist product name from
productViewModel.getAllProductForVendor
HTML
<div class="ui-block-a">
<h:selectOneMenu id="productname" value="#{productViewModel.prodname}" onchange="javascript: return this.form.submit();">
<f:selectItems value="#{productViewModel.getAllProductForVendor(vendorViewModel.vendorno)}"></f:selectItems>
</h:selectOneMenu>
</div>
Java Beans
public ArrayList<ProductEJBDTO> getAllProductForVendor(int vendorno) {
ArrayList<ProductEJBDTO> Products = new ArrayList() ;
//model.getProducts(vendorno);
try
{
Products = productFacadeBean.getAllProductsForVendor(vendorno);
}
catch(Exception e)
{
System.out.println("can't get products for vendors " + e);
}
return Products;
}
DTO
package case2dtos;
import java.io.Serializable;
import java.math.BigDecimal;
/**
*
* #author abdallaelnajjar
*/
public class ProductEJBDTO implements Serializable {
public ProductEJBDTO(){}
private int vendorno;
private String prodcd;
private String vensku;
private String prodnam;
private BigDecimal costprice;
private BigDecimal msrp;
private int rop;
private int eoq;
private int qoh;
private int qoo;
private byte[] qrcode;
/**
* #return the prodcd
*/
public String getProdcd() {
return prodcd;
}
/**
* #param prodcd the prodcd to set
*/
public void setProdcd(String prodcd) {
this.prodcd = prodcd;
}
/**
* #return the vensku
*/
public String getVensku() {
return vensku;
}
/**
* #param vensku the vensku to set
*/
public void setVensku(String vensku) {
this.vensku = vensku;
}
/**
* #return the prodnam
*/
public String getProdnam() {
return prodnam;
}
/**
* #param prodnam the prodnam to set
*/
public void setProdnam(String prodnam) {
this.prodnam = prodnam;
}
/**
* #return the costprice
*/
public BigDecimal getCostprice() {
return costprice;
}
/**
* #param costprice the costprice to set
*/
public void setCostprice(BigDecimal costprice) {
this.costprice = costprice;
}
/**
* #return the msrp
*/
public BigDecimal getMsrp() {
return msrp;
}
/**
* #param msrp the msrp to set
*/
public void setMsrp(BigDecimal msrp) {
this.msrp = msrp;
}
/**
* #return the rop
*/
public int getRop() {
return rop;
}
/**
* #param rop the rop to set
*/
public void setRop(int rop) {
this.rop = rop;
}
/**
* #return the eoq
*/
public int getEoq() {
return eoq;
}
/**
* #param eoq the eoq to set
*/
public void setEoq(int eoq) {
this.eoq = eoq;
}
/**
* #return the qoh
*/
public int getQoh() {
return qoh;
}
/**
* #param qoh the qoh to set
*/
public void setQoh(int qoh) {
this.qoh = qoh;
}
/**
* #return the qoo
*/
public int getQoo() {
return qoo;
}
/**
* #param qoo the qoo to set
*/
public void setQoo(int qoo) {
this.qoo = qoo;
}
/**
* #return the qrcode
*/
public byte[] getQrcode() {
return qrcode;
}
/**
* #param qrcode the qrcode to set
*/
public void setQrcode(byte[] qrcode) {
this.qrcode = qrcode;
}
/**
* #return the vendorno
*/
public int getVendorno() {
return vendorno;
}
/**
* #param vendorno the vendorno to set
*/
public void setVendorno(int vendorno) {
this.vendorno = vendorno;
}
}
Override the toString() method in the ProductEJBDTO to return the name.
public class ProductEJBDTO implements Serializable {
...
...
#Override
public String toString() {
return this.prodnam; // The product name you want to display.
}
}
Use the itemLabel attribute (docs):
<f:selectItems value="..." var="x" itemLabel="#{x.prodnam}"></f:selectItems>
(I assume the prodnam property is the desired display name; any EL expression will do though)
We have a memory leak problem, we don't know what/where too many instances of a certain class are created/referred from. This occurs under heavy load in production and we cannot obtain heap dump (taking heap dump hangs the HA server for too long time). Runtime profiling is also not an option on production site because of performance degradation, the customers are happier with a random crash rather than agonizing slow during monitoring trying to fish for the crash instant. We don't know how to initiate the crash (leak), it just occurs at some times.
Is there a way to obtain object referrers/instantiation points at runtime from within the application itself?
I looked at http://docs.oracle.com/javase/6/docs/jdk/api/jpda/jdi/com/sun/jdi/ObjectReference.html and it gives an idea that something like this could be possible.
Any pointers how to achieve this preferrably with custom code without the heap-dump-way? Reproducing the problem in test environment has been tried and it seems exhaustive wild goose-chase. We want now a brute force way to find the cause.
It is recommended that you try to check you code which is causing such leaks. Here are some tutorials and help regarding the same
IBM Article on Handling memory leaks in Java
http://www.ibm.com/developerworks/library/j-leaks/
Some other useful articles
http://www.openlogic.com/wazi/bid/188158/How-to-Fix-Memory-Leaks-in-Java
There is also an Eclipse Memory Analyser Tool
But the most recommended solution will be
Try running jvisualvm from the JVM on the same machine as your program is running and enable profiling.
We solved the issue by collecting stacktraces on instantiation and on clone.. and by dumping them on a scheduler and when memory goes low.
We know the Object class that causes the problem, just needed to hunt down where it is born:
#EntityListeners(AbstractDTOJpaEventListener.class)
#MappedSuperclass
public abstract class AbstractDTO implements Storeable, Serializable, Cloneable {
/** */
private static final String SHADOWED_CLASS = "Custom";
/** */
protected final static boolean DEBUG_CUSTOM_INSTANCES = true;
/** */
public static long TARGET_HITRATE_PER_INTERVAL = 400000;
/** */
public static long LOGGING_INTERVAL = Times.MILLISECONDS_IN_TEN_SECONDS;
/** */
private static long previousLoggingTime;
/** */
protected static int hits;
/** */
protected static boolean hitting;
/** */
protected static int hitsWithinInterval;
/**
* #author Martin
*/
public static class Hi {
/**
*
*/
private long hitted;
private final long createdAt;
private final StackTraceElement[] stackTraceElements;
private final String threadName;
/**
* #param threadName
* #param stackTraceElements
*/
public Hi(String threadName, StackTraceElement[] stackTraceElements) {
this.threadName = threadName;
this.createdAt = System.currentTimeMillis();
this.stackTraceElements = stackTraceElements;
}
/**
*
*/
public void hit() {
hitted++;
}
/**
* #return the hitted
*/
public long getHitted() {
return hitted;
}
/**
* #param hitted the hitted to set
*/
public void setHitted(long hitted) {
this.hitted = hitted;
}
/**
* #return the createdAt
*/
public long getCreatedAt() {
return createdAt;
}
/**
* #return the stackTraceElements
*/
public StackTraceElement[] getStackTraceElements() {
return stackTraceElements;
}
/**
* #return the threadName
*/
public String getThreadName() {
return threadName;
}
}
/** */
protected final static Map<String, Hi> INSTANCE_SHADOW = new ConcurrentHashMap<String, Hi>();
private static final Comparator<? super Entry<String, Hi>> COMPARATOR = new Comparator<Entry<String, Hi>>() {
#Override
public int compare(Entry<String, Hi> o1, Entry<String, Hi> o2) {
if (o1 == o2) {
return 0;
}
return -Utils.compareNullSafe(o1.getValue().getHitted(), o2.getValue().getHitted(), Compare.ARG0_FIRST);
}
};
/**
* #param <T>
* #return T
* #see java.lang.Object#clone()
*/
#SuppressWarnings("unchecked")
public <T extends AbstractDTO> T clone() {
try {
return (T) super.clone();
} catch (CloneNotSupportedException e) {
throw new RuntimeException(e);
} finally {
if (DEBUG_CUSTOM_INSTANCES && getClass().getSimpleName().equals(SHADOWED_CLASS)) {
shadowInstance();
}
}
}
/**
*
*/
protected void shadowInstance() {
if (DEBUG_CUSTOM_INSTANCES) {
final long currentTimeMillis = System.currentTimeMillis();
if (TARGET_HITRATE_PER_INTERVAL <= ++hitsWithinInterval) {
hitting = true;
}
if ((TARGET_HITRATE_PER_INTERVAL / 2) <= ++hits) {
final Thread currentThread = Thread.currentThread();
final StackTraceElement[] stackTrace = currentThread.getStackTrace();
final String key = Utils.getPropertyPath(String.valueOf(System.identityHashCode(currentThread)), displayStackLocaktion(stackTrace))
.intern();
Hi hi = INSTANCE_SHADOW.get(key);
if (hi == null) {
synchronized (key) {
hi = INSTANCE_SHADOW.get(key);
if (hi == null) {
INSTANCE_SHADOW.put(key, hi = new Hi(currentThread.getName(), stackTrace));
}
}
}
hi.hit();
}
{
if (getLoggingInterval(currentTimeMillis) != getLoggingInterval(previousLoggingTime)) {
if (hitsWithinInterval < TARGET_HITRATE_PER_INTERVAL) {
if (hitting) {
hitting = false;
} else {
hits = 0; // Reset measuring on second round, give chance to burtsy hits
}
}
hitsWithinInterval = 0;
previousLoggingTime = currentTimeMillis;
}
}
}
}
/**
* #param time
* #return long
*/
private long getLoggingInterval(long time) {
return time / LOGGING_INTERVAL;
}
/**
* #return String
*/
public static String toStringShadows() {
final ArrayList<Entry<String, Hi>> entries;
synchronized (INSTANCE_SHADOW) {
entries = Convert.toMinimumArrayList(INSTANCE_SHADOW.entrySet());
INSTANCE_SHADOW.clear();
}
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append(new Timestamp(System.currentTimeMillis()) + " " + SHADOWED_CLASS + " Class instance instantiantion summary:\n");
stringBuilder.append("hits=" + hits + ", hitting=" + hitting + ", hitsWithinInterval=" + hitsWithinInterval + ", previousLoggingTime=" + new java.sql.Timestamp(previousLoggingTime));
if (entries.isEmpty()) {
return stringBuilder.toString();
}
Collections.sort(entries, COMPARATOR);
int index = 0;
stringBuilder.append("-----------------------------------------------------------------------");
for (Entry<String, Hi> entry : entries) {
Utils.append(stringBuilder, entry.getValue().getHitted() + "\t" + entry.getKey(), "\n");
}
for (Entry<String, Hi> entry : entries) {
final Hi hi = entry.getValue();
final StackTraceElement[] stackTrace = hi.getStackTraceElements();
final String groupName = entry.getKey();
final String threadName = hi.getThreadName();
stringBuilder.append("\n").append(++index).append('\t');
stringBuilder.append(hi.getHitted()).append("\tpcs\t").append(groupName);
stringBuilder.append("\t").append(new Timestamp(hi.getCreatedAt()).toString()).append('\t').append(threadName)
.append('\t').append(Convert.toString(stackTrace));
}
return stringBuilder.toString();
}
/**
* #param stackTrace
* #return String
*/
private static String displayStackLocaktion(final StackTraceElement[] stackTrace) {
StackTraceElement firstDistinguishingStackTraceElement = null;
for (int index = 0; index < stackTrace.length; index++) {
firstDistinguishingStackTraceElement = stackTrace[index];
if (!Arrays.asList(UNWANTED_LOCATIONS).contains(firstDistinguishingStackTraceElement.getClassName())) {
break;
}
}
StackTraceElement lastDistinguishingStackTraceElement = null;
for (int index = stackTrace.length-1; 0 <= index; index--) {
lastDistinguishingStackTraceElement = stackTrace[index];
if (lastDistinguishingStackTraceElement.getClassName().startsWith(OUR_PACKAGE_DOMAIN)) {
break;
}
}
return Utils.getPropertyPath(displayName(firstDistinguishingStackTraceElement) + "<-"
+ displayName(lastDistinguishingStackTraceElement));
}
/**
* #param firstDistinguishingStackTraceElement
* #return String
*/
private static String displayName(StackTraceElement firstDistinguishingStackTraceElement) {
return Utils.getPropertyPath(firstDistinguishingStackTraceElement.getClassName(), firstDistinguishingStackTraceElement.getMethodName(),
String.valueOf(firstDistinguishingStackTraceElement.getLineNumber()));
}
}