Primefaces Multiple FileUpload doesn't show files nor triggers the handleFileUpload - file-upload

I'm searching since one week and couldn't find a proper solution for my problem. So I'm asking the experts here.
I'm trying to implement a page with FileUpload to upload and show the images after upload on same page.
my problem is, if I set my ManagedBean to #RequestScope, the handleFileUpload function will not be triggered.
If I set it to #ViewScope, the function will be triggered but the error "Error in streaming dynamic resource." is shown.
here are my files:
web.xml
<filter>
<filter-name>PrimeFaces FileUpload Filter</filter-name>
<filter-class>org.primefaces.webapp.filter.FileUploadFilter</filter-class>
<init-param>
<param-name>thresholdSize</param-name>
<param-value>2097152</param-value>
</init-param>
<init-param>
<param-name>uploadDirectory</param-name>
<param-value>E:/uploadedImages</param-value>
</init-param>
PrimeFaces FileUpload Filter
Faces Servlet
Bean
#ManagedBean
#RequestScoped
public class ImageManager implements Serializable {
private final static int MAX_UPLOADED_FILES = 5;
private final static String UPLOADED_FILES_PATH = "E:/uploadedImages";
private final Map<UUID, UploadedFile> uploadedFiles = new HashMap<>();
public List<String> getListImages() {
final List<String> result = new ArrayList<>();
for (final UUID uuid : uploadedFiles.keySet())
result.add(uuid.toString());
return result;
}
public StreamedContent getImage() {
final ExternalContext externalContext = FacesContext.getCurrentInstance().getExternalContext();
final String imageId = (String) externalContext.getRequestMap().get("imageId");
if (imageId != null) {
final UUID imageIndex = UUID.fromString(imageId);
return new DefaultStreamedContent(new ByteArrayInputStream(uploadedFiles.get(imageIndex).getContents()), "image/jpg");
}
return null;
}
public void handleFileUpload(FileUploadEvent event) {
if (uploadedFiles.size() < MAX_UPLOADED_FILES) {
final UploadedFile uploadedFile = event.getFile();
if (uploadedFile != null) {
uploadedFiles.put(UUID.randomUUID(), uploadedFile);
}
}
}
}
xhtml
<p:fileUpload fileUploadListener="#{imageManager.handleFileUpload}"
mode="advanced"
multiple="true"
sizeLimit="2097152"
allowTypes="/(\.|\/)(gif|jpe?g|png)$/"
uploadLabel="Hochladen"
auto="false"
cancelLabel="Abbrechen"
invalidFileMessage="Die ausgewählte Datei ist kein zugelassene Bilddatei"
invalidSizeMessage="Die maximale Bildgröße ist 2MB"
label="Datei Auswählen"
update="imageList"
/>
<ui:repeat value="#{imageManager.listImages}" var="imageId" id="imageList">
<h:outputText value="#{imageId}" />
<p:graphicImage value="#{imageManager.image}">
<f:param id="imageId" name="imageId" value="#{imageId}" />
</p:graphicImage>
</ui:repeat>

#Daniel, blieve me. I've searched many days before I post my question here. But I have resolved the Problem by myself.
here is the solution in case that somebody has the same problem:
#Controller
#Scope(WebApplicationContext.SCOPE_REQUEST)
public class ImageManager implements Serializable {
private final static int MAX_UPLOADED_FILES = 5;
private final static String UPLOADED_FILES_PATH = "E:/uploadedImages";
private final static Map<UUID, UploadedFile> uploadedFiles = new HashMap<>();
private final static List<String> listImages = new ArrayList<>();
private StreamedContent image;
private static StreamedContent defaultImage = null;
static {
try {
defaultImage = new DefaultStreamedContent(new FileInputStream(new File("E:\\uploadedImages\\t.jpg")), "image/jpg");
}
catch (FileNotFoundException e) {
e.printStackTrace();
}
}
public List<String> getListImages() {
return listImages;
}
public StreamedContent getImage() {
final ExternalContext externalContext = FacesContext.getCurrentInstance().getExternalContext();
final String imageId = (String) externalContext.getRequestParameterMap().get("imageId");
if (imageId != null) {
final UUID imageIndex = UUID.fromString(imageId);
image = new DefaultStreamedContent(new ByteArrayInputStream(uploadedFiles.get(imageIndex).getContents()), "image/jpg");
return image;
}
return defaultImage;
}
public void handleFileUpload(FileUploadEvent event) {
if (uploadedFiles.size() < MAX_UPLOADED_FILES) {
final UploadedFile uploadedFile = event.getFile();
if (uploadedFile != null) {
final UUID uuid = UUID.randomUUID();
uploadedFiles.put(uuid, uploadedFile);
listImages.add(uuid.toString());
}
}
}
public void setImage(StreamedContent image) {
this.image = image;
}
}

Related

Add weights to documents Lucene8+solr 8 while indexing

I am working on migrating solr from 5.4.3 to 8.11 for one of my search apps and successfully upgraded to 7.7.3. But for further upgradations facing the order of the response data being changed than it was earlier. Here I am trying to use FunctionScoreQuery along with DoubleValuesSource since CustomScoreQuery is deprecated in 7.7.3 and removed in 8.
Below is my code snippet (now I am using solr 8.5.2 and Lucene 8.5.2)
public class CustomQueryParser extends QParserPlugin {
#Override
public QParser createParser(final String qstr, final SolrParams localParams, final SolrParams params,
final SolrQueryRequest req) {
return new MyParser(qstr, localParams, params, req);
}
private static class MyParser extends QParser {
private Query innerQuery;
private String queryString;
public MyParser(final String qstr, final SolrParams localParams, final SolrParams params,
final SolrQueryRequest req) {
super(qstr, localParams, params, req);
if (qstr == null || qstr.trim().length() == 0) {
this.queryString = DEFAULT_SEARCH_QUERY;
setString(this.queryString);
} else {
this.queryString = qstr;
}
try {
if (queryString.contains(":")) {
final QParser parser = getParser(queryString, "edismax", getReq());
this.innerQuery = parser.parse();
} else {
final QParser parser = getParser(queryString, "dismax", getReq());
this.innerQuery = parser.parse();
}
} catch (final SyntaxError ex) {
throw new RuntimeException("Error parsing query", ex);
}
}
#Override
public Query parse() throws SyntaxError{
final Query query = new MyCustomQuery(innerQuery);
final CustomValuesSource customValuesSource = new CustomValuesSource(queryString,innerQuery);
final FunctionScoreQuery fsq = FunctionScoreQuery.boostByValue(query, customValuesSource.fromFloatField("score"));
return fsq;
}
}
}
public class MyCustomQuery extends Query {
#Override
public Weight createWeight(final IndexSearcher searcher, final ScoreMode scoreMode, final float boost) throws IOException {
Weight weight;
if(query == null){
weight = new ConstantScoreWeight(this, boost) {
#Override
public Scorer scorer(final LeafReaderContext context) throws IOException {
return new ConstantScoreScorer(this,score(),scoreMode, DocIdSetIterator.all(context.reader().maxDoc()));
}
#Override
public boolean isCacheable(final LeafReaderContext leafReaderContext) {
return false;
}
};
}else {
weight = searcher.createWeight(query,scoreMode,boost);
}
return weight;
}
}
public class CustomValuesSource extends DoubleValuesSource {
#Override
public DoubleValues getValues(final LeafReaderContext leafReaderContext,final DoubleValues doubleValues) throws IOException {
final DoubleValues dv = new CustomDoubleValues(leafReaderContext);
return dv;
}
class CustomDoubleValues extends DoubleValues {
#Override
public boolean advanceExact(final int doc) throws IOException {
final Document document = leafReaderContext.reader().document(doc);
final List<IndexableField> fields = document.getFields();
for (final IndexableField field : fields) {
// total_score is being calculated with my own preferences
document.add(new FloatDocValuesField("score",total_score));
//can we include the **score** here?
this custom logic which includes score is not even calling.
}
}
}
I am trying for a long time but have not found a single working example. Can anybody help me and save me here.
Thank you,
Syamala.

Set RecyclerView itemTextView programmatically to BOLD based on Volley JSON response?

I populate a RecyclerView from JSON data pulled from a webserver using Volley. I have two columns called user1Read and user2Read that is yes or no. I would like to know how I can modify my Adapter to set the TypeFace to bold if the message is considered "unread"? I am unsure of how to access the TextView from within my onResponse logic. Should I create a member variable in my Messages model class? Should I create it in my Adapter? Where would be the best place to put this? In my JSON onResponse, it would be great if I could just say
onResponseMethod {
if(!hasRead) {
//set TypeFace BOLD here
//But how to access TextView???
}
}
My custom Adapter:
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Filter;
import android.widget.Filterable;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import com.squareup.picasso.Picasso;
import java.util.ArrayList;
import de.hdodenhof.circleimageview.CircleImageView;
public class MessageAdapter extends RecyclerView.Adapter<MessageAdapter.ViewHolder> implements Filterable {
private ArrayList<Message> messages;
private OnItemClickListener mListener;
#Override
public Filter getFilter() {
return null;
}
public interface OnItemClickListener {
void onItemClick(int position);
}
public void setOnItemClickListener(OnItemClickListener listener) {
mListener = listener;
}
public MessageAdapter(ArrayList<Message> messages) {
this.messages = messages;
}
#NonNull
#Override
public ViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.message_list_item, parent, false);
return new ViewHolder(v);
}
#Override
public void onBindViewHolder(#NonNull ViewHolder holder, int position) {
Message message = messages.get(position);
holder.username.setText(message.getUsername());
holder.messageSnippet.setText(message.getMessageSnippet());
holder.singleMessageTimestamp.setText(message.getTimestamp());
Picasso.get().load(message.getAvatarUrl()).into(holder.avatarCircleImageView);
}
#Override
public int getItemCount() {
if (messages != null) {
return messages.size();
} else {
return 0;
}
}
public class ViewHolder extends RecyclerView.ViewHolder {
public final View view;
public final TextView username;
public final TextView messageSnippet;
public final TextView singleMessageTimestamp;
public final CircleImageView avatarCircleImageView;
public ViewHolder(View view) {
super(view);
this.view = view;
username = view.findViewById(R.id.message_item_username_textview);
messageSnippet = view.findViewById(R.id.message_item_message_snippet_textview);
singleMessageTimestamp = view.findViewById(R.id.message_item_timestamp);
avatarCircleImageView = view.findViewById(R.id.message_item_circle_avatar);
view.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (mListener != null) {
int position = getAdapterPosition();
if (position != RecyclerView.NO_POSITION) {
mListener.onItemClick(position);
}
}
}
});
}
}
}
My Message Model:
import android.widget.ImageView;
public class Message {
private String username;
private String messageSnippet;
private String avatarUrl;
private String timestamp;
private ImageView dot;
public Message(String username, String message, String avatar, String timestamp) {
this.username = username;
this.messageSnippet = message;
this.avatarUrl = avatar;
this.timestamp = timestamp;
}
public Message(String username, String avatar) {
this.username = username;
this.avatarUrl = avatar;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getMessageSnippet() {
return messageSnippet;
}
public void setMessageSnippet(String messageSnippet) {
this.messageSnippet = messageSnippet;
}
public String getTimestamp() {
return timestamp;
}
public void setTimestamp(String timestamp) {
this.timestamp = timestamp;
}
public String getAvatarUrl() {
return avatarUrl;
}
public void setAvatarUrl(String avatarUrl) {
this.avatarUrl = avatarUrl;
}
}
My main Activity (MessagesActivity).
public class MessagesActivity extends AppCompatActivity implements MessageAdapter.OnItemClickListener {
private RecyclerView messages;
private MessageAdapter adapter;
private ImageView circle_avatar;
private TextView header_username_text;
private ImageView avatar;
private TextView username_heading;
private static JSONArray profile_array;
private static final String TAG = "MessagesActivity";
private static final String getMessagesUrl = "https://myURL.com/get_messages.php";
private static String username;
private static ProgressDialog messagesProgressDialog;
private static ArrayList<Message> list = new ArrayList<>();
private static JSONObject jsonObject;
private static Timer updateTimer;
private static String hasRead;
private static RecyclerView.LayoutManager mLayoutManager;
private DrawerLayout mDrawerLayout;
private ImageButton composeImageButton;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_messages);
configureNavigationDrawer();
configureToolbar();
if(list != null) {
list.clear();
}
avatar = findViewById(R.id.profile_avatar);
username_heading = findViewById(R.id.username_text);
updateTimer = new Timer();
TimerTask updateTimerTask = new TimerTask() {
public void run() {
refreshMessages();
}
};
updateTimer.scheduleAtFixedRate(updateTimerTask, 3000, 3000);
messagesProgressDialog = new ProgressDialog(MessagesActivity.this, R.style.Custom_Progress_Dialog);
messagesProgressDialog.setIndeterminate(true);
messagesProgressDialog.setMessage("Fetching Messages...");
messagesProgressDialog.show();
SharedPreferences sharedPreferences = this.getSharedPreferences("MyPref", MODE_PRIVATE);
username = sharedPreferences.getString("username", null);
getProfile(username);
messages = findViewById(R.id.messages);
messages.addItemDecoration(new DividerItemDecoration(this, LinearLayout.VERTICAL));
ArrayList<Message> messages = initMessages();
mLayoutManager = new LinearLayoutManager(this);
this.messages.setLayoutManager(mLayoutManager);
adapter = new MessageAdapter(messages);
this.messages.setAdapter(adapter);
adapter.setOnItemClickListener(this);
getProfile(username);
composeImageButton = findViewById(R.id.custom_toolbar_image_button);
composeImageButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Log.d(TAG, "Clicked compose Image Button");
Intent composeIntent = new Intent(MessagesActivity.this, ComposeActivity.class);
startActivity(composeIntent);
updateTimer.cancel();
updateTimer.purge();
}
});
}
private ArrayList<Message> initMessages() {
RequestQueue messagesQueue = Volley.newRequestQueue(this);
StringRequest messagesRequest = new StringRequest(Request.Method.POST, getMessagesUrl, new Response.Listener<String>() {
#Override
public void onResponse(String response) {
messagesProgressDialog.dismiss();
try {
String baseUrl = "https://myURL.com";
String defaultbaseUrl = "https://myURL.com/css/images/user_default/default_avatar.png";
JSONObject responseObject = new JSONObject(response);
JSONArray responseArray = responseObject.getJSONArray("data");
for(int i = 0; i < responseArray.length(); i++) {
jsonObject = responseArray.getJSONObject(i);
hasRead = jsonObject.getString("has_read");
String avatar = jsonObject.getString("avatar");
String message = jsonObject.getString("message");
String sender = jsonObject.getString("sender");
String timestamp = jsonObject.getString("timestamp");
Log.d(TAG, "sender: "+sender+", hasRead: "+hasRead);
if(avatar.contains("../users")) {
String substring = avatar.substring(avatar.indexOf(".") + 2);
avatar = baseUrl+substring;
Log.d(TAG, "if(avatar.contains('../users'): "+avatar);
} else {
avatar = defaultbaseUrl;
}
list.add(new Message(sender, message, avatar, timestamp));
}
updateData();
} catch(Exception e) {
Log.d(TAG, "EXCEPTION: "+e.getMessage());
}
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
Log.d(TAG, "VolleyError: "+error.getMessage());
messagesProgressDialog.dismiss();
}
}) {
#Override
public Map<String, String> getParams() {
Map<String, String> params = new HashMap<>();
params.put("username", username);
return params;
}
};
messagesQueue.add(messagesRequest);
return list;
}
/*
Called with TimerTask
*/
private void refreshMessages() {
RequestQueue updateQueue = Volley.newRequestQueue(this);
StringRequest updateRequest = new StringRequest(Request.Method.POST, getMessagesUrl, new Response.Listener<String>() {
#Override
public void onResponse(String response) {
list.clear();
try {
String baseUrl = "https://myURL.com";
String defaultbaseUrl = "https://myURL.com/css/images/user_default/default_avatar.png";
JSONObject updateObject = new JSONObject(response);
JSONArray updateResponseArray = updateObject.getJSONArray("data");
for (int i = 0; i < updateResponseArray.length(); i++) {
updateObject = updateResponseArray.getJSONObject(i);
hasRead = updateObject.getString("has_read");
String avatar = updateObject.getString("avatar");
String message = updateObject.getString("message");
String sender = updateObject.getString("sender");
String timestamp = updateObject.getString("timestamp");
if (avatar.contains("../users")) {
String substring = avatar.substring(avatar.indexOf(".") + 2);
avatar = baseUrl + substring;
} else {
avatar = defaultbaseUrl;
}
if(hasRead.equals("no")) {
}
list.add(new Message(sender, message, avatar, timestamp));
}
updateData();
adapter.notifyDataSetChanged();
} catch(Exception e) {
Log.d(TAG, "EXCEPTION: "+e.getMessage());
}
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
Log.d(TAG, "VolleyError: "+error.getMessage());
}
}) {
#Override
public Map<String, String> getParams() {
Map<String, String> params = new HashMap<>();
params.put("username", username);
return params;
}
};
updateQueue.add(updateRequest);
}
#Override
public void onBackPressed() {
super.onBackPressed();
list.clear();
updateTimer.cancel();
updateTimer.purge();
SharedPreferences prefs = MessagesActivity.this.getSharedPreferences("MyPref", MODE_PRIVATE);
prefs.edit().putBoolean("is_logged_in", false).apply();
finish();
}
#Override
protected void onResume() {
super.onResume();
}
public void updateData() {
ArrayList<Message> strs = new ArrayList<>();
for(int i = 0; i < list.size(); i++) {
strs.add(list.get(i));
MessageAdapter updateAdapter = new MessageAdapter(list);
messages = findViewById(R.id.messages);
messages.setAdapter(updateAdapter);
updateAdapter.setOnItemClickListener(this);
}
}
#Override
public void onItemClick(int position) {
Log.d(TAG, "onItemClick Called");
Intent conversationIntent = new Intent(MessagesActivity.this, ConversationActivity.class);
String recipient = ((TextView) Objects.requireNonNull(messages.findViewHolderForAdapterPosition(position)).itemView.findViewById(R.id.message_item_username_textview)).getText().toString();
conversationIntent.putExtra("recipient", recipient);
conversationIntent.putExtra("username", username);
updateTimer.cancel();
updateTimer.purge();
startActivity(conversationIntent);
list.clear();
finish();
}
public void getProfile(final String username) {
final String username_url = "https://myURL.com/get_profile.php?username=" + username;
RequestQueue queue = Volley.newRequestQueue(this);
StringRequest postRequest = new StringRequest(Request.Method.GET, username_url,
new com.android.volley.Response.Listener<String>() {
#Override
public void onResponse(String response) {
String baseUrl = "https://myURL.com";
String defaultbaseUrl = "https://myURL.com/css/images/user_default/default_avatar.png";
try {
profile_array = new JSONArray(response);
for(int i = 0; i < profile_array.length(); i++) {
Log.d(TAG, "getProfile inside for loop");
JSONObject jsonObject = profile_array.getJSONObject(i);
String name = jsonObject.getString("name");
String avatarString = jsonObject.getString("avatar");
Log.d(TAG, "getProfile avatarString: "+avatarString);
if(avatarString.contains("../users")) {
String substring = avatarString.substring(avatarString.indexOf(".") + 2);
Log.d(TAG, "substring: "+substring);
String urlString = baseUrl +substring;
Picasso.get().load(urlString).into(circle_avatar);
Log.d(TAG, "urlString: "+urlString);
//Log.d(TAG, "CircleImageView getDrawable(): "+avatar.getDrawable());
header_username_text.setText(name);
} else {
Picasso.get().load(defaultbaseUrl).into(circle_avatar);
header_username_text.setText(name);
}
}
} catch (JSONException e) {
ToastMaker.createLongToast(getApplicationContext(), "JSONException getProfile: "+ e.getMessage());
}
}
},
new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
// error
Log.d(TAG, "VolleyError: "+error.getMessage());
//Toast.makeText(getApplicationContext(), TAG + " " + error, Toast.LENGTH_LONG).show();
}
}
) {
#Override
protected Map<String, String> getParams() {
Map<String, String> params = new HashMap<>();
return params;
}
};
queue.add(postRequest);
}
public void showLogoutDialog() {
AlertDialog.Builder logoutBuilder = new AlertDialog.Builder(this, R.style.Custom_Alert_Dialog);
logoutBuilder.setIcon(R.mipmap.ic_launcher_foreground);
logoutBuilder.setTitle("Confirm Logout");
logoutBuilder.setMessage("You are about to logout.\nAre you sure?")
.setCancelable(true)
.setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
SharedPreferences prefs = MessagesActivity.this.getSharedPreferences("MyPref", MODE_PRIVATE);
prefs.edit().putBoolean("is_logged_in", false).apply();
Intent logoutIntent = new Intent(MessagesActivity.this, LoginActivity.class);
startActivity(logoutIntent);
finish();
}
}).setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
dialog.cancel();
}
});
AlertDialog alertDialog = logoutBuilder.create();
alertDialog.show();
}
private void configureNavigationDrawer() {
mDrawerLayout = findViewById(R.id.drawer_layout);
NavigationView navigationView = findViewById(R.id.navigation_view);
circle_avatar = navigationView.getHeaderView(0).findViewById(R.id.profile_circle_avatar);
header_username_text = navigationView.getHeaderView(0).findViewById(R.id.header_username_text);
navigationView.setNavigationItemSelectedListener(new NavigationView.OnNavigationItemSelectedListener() {
#Override
public boolean onNavigationItemSelected(#NonNull MenuItem menuItem) {
switch (menuItem.getItemId()) {
case R.id.edit_profile:
//String name = username_heading.getText().toString();
//String pic = avatar.getDrawable().toString();
//String location = location_heading.getText().toString();
//String interests = interests_heading.getText().toString();
//editProfile(name, pic, location, interests);
Log.d(TAG, "Clicked Edit Profile");
break;
case R.id.messages:
Log.d(TAG, "Clicked Messages");
mDrawerLayout.closeDrawers();
break;
case R.id.privacy:
Intent privacyIntent = new Intent(MessagesActivity.this, PrivacyActivity.class);
startActivity(privacyIntent);
Log.d(TAG, "Clicked Privacy");
break;
case R.id.logout:
showLogoutDialog();
Log.d(TAG, "Clicked Logout Button");
break;
}
mDrawerLayout.closeDrawers();
return false;
}
});
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
int itemId = item.getItemId();
switch(itemId) {
case android.R.id.home:
mDrawerLayout.openDrawer(GravityCompat.START);
return true;
}
return true;
}
private void configureToolbar() {
Toolbar toolbar = findViewById(R.id.custom_toolbar);
setSupportActionBar(toolbar);
ActionBar actionBar = getSupportActionBar();
assert actionBar != null : Log.d(TAG, "actionBar is NULL");
actionBar.setDisplayShowTitleEnabled(false);
actionBar.setHomeAsUpIndicator(R.drawable.ic_action_menu_24dp);
actionBar.setDisplayHomeAsUpEnabled(true);
}
#Override
protected void onRestart() {
super.onRestart();
updateTimer = new Timer();
TimerTask updateTimerTask = new TimerTask() {
public void run() {
refreshMessages();
}
};
updateTimer.scheduleAtFixedRate(updateTimerTask, 3000, 3000);
}
}
Here is the array that is being sent from the webserver:
$data[] = array('has_read' => 'no', 'avatar' => $avatar, 'sender' => $sender, 'recipient' => $recipient, 'message' => $message, 'timestamp' => $time);
$response = array('data'=>$data, 'count'=>$count);
echo json_encode($response);
If you need only one Boolean throughout your app, here is a way to access the Boolean value:
Create a separate file named ext for example and inside, make this interface:
public interface ext {
Boolean hasRead = false;
}
This variable is made when the app runs and lives for as long as the app does. so you can change it whenever you want.
If you want to have 2 separate Booleans for the two users chatting you can use a Hashmap like so:
HashMap <String, Boolean> readStatus = new HashMap<>();
Update 2
Guess what? It was a typo in another php function not mentioned in my question called getConversation(). I stopped working on the file a while back to perfect my MessagesActivity. I logged any Exceptions on the Activity, and noticed Exception in getMessages(): No value for timestamp.
I had misspelled my timestamp variable. Lol. So, I have a fully functioning messaging system now! :-) Now to work on some notification bells and whistles. Have a great weekend.
Update: This is not completely solved. It's
bold when it's initially received on the MessagesActivity screen, but it goes back to regular Typeface once they refresh (via the TimerTask). Will debug for a while and come back, unless one of you discovers it first. :)
I think I figured it out!
My table is like so:
user1, user1ID, user2, user2ID, message, timestamp, user1read, user2read
When I make my request for a message, I receive these items via the php script:
if($sender === $username) {
$data[] = array('has_read'=>$user1read, 'avatar'=>$avatar, 'sender'=>$recipient, 'message'=>'You: '.$message, 'timestamp'=>$time);
} else {
$data[] = array('has_read' => $user2read, 'avatar' => $avatar, 'sender' => $sender, 'recipient' => $recipient, 'message' => $message, 'timestamp' => $time);
}
This was my original loop to get all the messages from my JSONObject:
for (int i = 0; i < updateResponseArray.length(); i++) {
updateObject = updateResponseArray.getJSONObject(i);
String hasRead = updateObject.getString("has_read");
String avatar = updateObject.getString("avatar");
String message = updateObject.getString("message");
String sender = updateObject.getString("sender");
String timestamp = updateObject.getString("timestamp");
if (avatar.contains("../users")) {
String substring = avatar.substring(avatar.indexOf(".") + 2);
avatar = baseUrl + substring;
} else {
avatar = defaultbaseUrl;
}
list.add(new Message(sender, message, avatar, timestamp));
So, I thought, "why don't I just create another member variable for my Messages model, and call it "hasRead"? So I did just that:
public class Message {
private String username;
private String messageSnippet;
private String avatarUrl;
private String timestamp;
private String hasRead; //<--- here we go
Then I make my getters and setters (leaving out for the sake of brevity).
#J7bits suggested I access the onBindViewHolder() in my custom Adapter class. So I did that, but I included logic to check the status of the new member variable "hasRead":
#Override
public void onBindViewHolder(#NonNull ViewHolder holder, int position) {
Message message = messages.get(position);
holder.username.setText(message.getUsername());
holder.messageSnippet.setText(message.getMessageSnippet());
holder.singleMessageTimestamp.setText(message.getTimestamp());
Picasso.get().load(message.getAvatarUrl()).into(holder.avatarCircleImageView);
if(message.getHasRead().equals("no")) {
holder.messageSnippet.setTypeface(null, Typeface.BOLD_ITALIC);
}
}
Then, finally, I changed my JSON onResponse method to include the has_read variable sent from php:
String hasRead = jsonObject.getString("has_read");
And I added it to my ArrayList<Message> list:
list.add(new Message(sender, message, avatar, timestamp, **hasRead**);
I entered a new message manually into the database, and set my status to "no" for user2read. And would you just look at it?!?! :D

Populating RecyclerView with parsed JSON. onPostExecute error

I have created a HTTPManager class to make the GET request to download a simple JSON file from http://dev1.digitalnativeshq.com/userJSONtest.json
In ASyncTask, the GET request is made and a string is returned. That string is parsed by the JSONParser class. JSONParser returns a array of User objects. In onPostExecute I want to set the adapter data to the information that is downloaded and parsed in doInBackGround. I am getting an error when I try
adapter = new ContactAdapter(MainActivity.this, contactList);
MainActivity.java
public class MainActivity extends Activity {
private ContactAdapter adapter;
private static String testURL = "http://dev1.digitalnativeshq.com/userJSONtest.json";
private RecyclerView rView;
private List<ContactInfo> contactList = new ArrayList<>();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
RecyclerView rView = (RecyclerView)findViewById(R.id.list);
rView.setHasFixedSize(true);
LinearLayoutManager layout = new LinearLayoutManager(this);
layout.setOrientation(LinearLayoutManager.VERTICAL);
rView.setLayoutManager(layout);
fillRecyclerview task = new fillRecyclerview();
task.execute();
}
private class fillRecyclerview extends AsyncTask<Void, Void, List<ContactInfo>>{
#Override
protected List<ContactInfo> doInBackground(Void... params) {
String json = HTTPManager.getData(testURL);
contactList = JSONParser.parseFeed(json);
return contactList;
}
#Override
protected void onPostExecute(List<ContactInfo> result){
adapter = new ContactAdapter(MainActivity.this, contactList);
rView.setAdapter(adapter);
}
}
JSONParser.java
public class JSONParser {
public static List<ContactInfo> parseFeed(String content){
try {
JSONArray ar = new JSONArray(content);
List<ContactInfo> userList = new ArrayList<>();
//iterate through JSON object and set fields to strings
for (int i = 0; i < ar.length(); i++) {
JSONObject obj = ar.getJSONObject(i);
ContactInfo user = new ContactInfo();
user.setName(obj.getString("name"));
user.setEmail(obj.getString("email"));
userList.add(user);
}
return userList;
} catch (JSONException e) {
e.printStackTrace();
return null;
}
}
ContactAdapter.java
public class ContactAdapter extends RecyclerView.Adapter<ContactAdapter.ContactViewHolder> {
private List<ContactInfo> contactList;
public ContactAdapter(List<ContactInfo> contactList) {
this.contactList = contactList;
}
#Override
public int getItemCount() {
return contactList.size();
}
public static class ContactViewHolder extends RecyclerView.ViewHolder {
protected TextView vName;
protected TextView vEmail;
public ContactViewHolder(View v) {
super(v);
vName = (TextView) v.findViewById(R.id.name);
vEmail = (TextView) v.findViewById(R.id.email);
}
}
#Override
public void onBindViewHolder(ContactViewHolder contactViewHolder, int i) {
ContactInfo ci = contactList.get(i);
contactViewHolder.vName.setText(ci.name);
contactViewHolder.vEmail.setText(ci.email);
}
//select XML layout for each card
#Override
public ContactViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
View itemView = LayoutInflater.
from(viewGroup.getContext()).
inflate(R.layout.cardview, viewGroup, false);
return new ContactViewHolder(itemView);
}
}
HTTPManager.java
public class HTTPManager {
public static String getData(String uri){
BufferedReader reader = null;
try{
URL url = new URL(uri);
HttpURLConnection con = (HttpURLConnection) url.openConnection();
StringBuilder sb = new StringBuilder();
reader = new BufferedReader(new InputStreamReader(con.getInputStream()));
String line;
while((line = reader.readLine()) != null){
sb.append(line + "\n");
}
return sb.toString();
} catch (Exception e){
e.printStackTrace();
return null;
} finally {
if (reader == null) {
try {
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
In your MainActivity.java you get the List<ContactInfo> called result. But when using the adapter you are using contactList like in the doInBackground.
#Override
protected void onPostExecute(List<ContactInfo> result){
adapter = new ContactAdapter(MainActivity.this, contactList);
rView.setAdapter(adapter);
}
don't know if that will fix it but did you try this?
#Override
protected void onPostExecute(List<ContactInfo> result){
adapter = new ContactAdapter(MainActivity.this, result);
rView.setAdapter(adapter);
}

Jersey 2.6 #QueryParam is missing from #BeanParam when using MOXY but not with Jackson

I am developing a set of REST web services for my company. We are trying to settle on what technologies we want to use.
I have a template web service that works with JAX-RS Jersey 2.6 when I use the Jackson JSON providers, but doesn't seem to marshal the #QueryParam correctly when I use the Moxy providers.
The search may include multiple "types" such as type=keyword&type=product_number&type=fubar
These are mapped to the List types which contains all of the "type" QueryParam. When I build the project with Jackson, the values of type are correctly collected into the List, when I use MOXy the List is null. MOXy does map all of the other Query and Path Params in the BeanParam.
The problem seems to be in how JERSEY is
When I use Jackson the service works great:
http://XXX:8080/SearchTermJersey/search/1/as/wat?type=product_number&type=keyword&count=4&lang=en_US
This is the JSON it returned:
{"autoSuggestions":{"product_number":{"<span>wat</span>21000":34},"keyword":{"<span>wat</span>er":100,"<span>wat</span>er solution":50,"<span>wat</span>er purity":100}},"language":"en_US","requestDate":1393623225135,"responseDate":1393623225135,"term":"wat","version":"1"}
The URL for the Moxy version of the service returns:
{"language":"en_US","requestDate":1393622174166,"responseDate":1393622174166,"term":"wat","version":"1"}
The Java code is identical between the MOXy and Jackson versions
This is the BeanParam:
public class AutoSuggestParam {
#PathParam("version")
private String version;
#PathParam("term")
private String term;
private List<String>types;
private Integer count;
String language;
public AutoSuggestParam(#QueryParam("count")int count, #QueryParam("type")List<String>types, #QueryParam("lang")String language) {
this.types = types;
this.count = count;
this.language = language;
}
public String getVersion() {
return version;
}
public void setVersion(String version) {
this.version = version;
}
public String getTerm() {
return term;
}
public void setTerm(String term) {
this.term = term;
}
public Integer getCount() {
return count;
}
public String getLanguage() {
return language;
}
public List<String>getTypes() {
return types != null ? types : new ArrayList<String>();
}
The problem seems to be in how the types parameter is handled. With Jackson the types QueryParams are correctly marshalled into the List, but MOXy fails and just returns a null. So getTypes is returning an empty List. The simple QueryParam count and lang are handled correctly. Is this a bug in Jersey or do I need to do something else with MOXy?
Here is my Resource class:
#javax.ws.rs.Path("/search/{version}/as/{term}")
public class AutoSuggestResource {
#GET
#Produces(MediaType.APPLICATION_JSON)
public AutoSuggestResponse getAutoSuggest(#BeanParam AutoSuggestParam autoSuggestParam) {
System.out.printf("Request: term=%s version=%s lang=%s type=%s count=%d%n",
autoSuggestParam.getTerm(),autoSuggestParam.getVersion(), autoSuggestParam.getLanguage(), autoSuggestParam.getTypes().get(0), autoSuggestParam.getCount());
return search(autoSuggestParam);
}
private AutoSuggestResponse search(AutoSuggestParam autoSuggestParam) {
AutoSuggestResponse autoSuggestResponse = new AutoSuggestResponse();
autoSuggestResponse.setRequestDate(new Date().getTime());
autoSuggestResponse.setVersion(autoSuggestParam.getVersion());
autoSuggestResponse.setTerm(autoSuggestParam.getTerm());
autoSuggestResponse.setLanguage(autoSuggestParam.getLanguage());
int cnt = 0;
for (String type : autoSuggestParam.getTypes()) {
if ("product_number".equals(type)) {
Map<String, Object> values = autoSuggestResponse.getAutoSuggestions().get(type);
if (values == null) {
values = new LinkedHashMap<String, Object>();
autoSuggestResponse.getAutoSuggestions().put(type, values);
}
String key = String.format("<span>%s</span>21000", autoSuggestParam.getTerm());
values.put(key, 34);
cnt++;
}
else if ("keyword".equals(type)) {
Map<String, Object> values = autoSuggestResponse.getAutoSuggestions().get(type);
if (values == null) {
values = new LinkedHashMap<String, Object>();
autoSuggestResponse.getAutoSuggestions().put(type, values);
}
String key = String.format("<span>%s</span>er", autoSuggestParam.getTerm());
values.put(key, 100);
cnt++;
key = String.format("<span>%s</span>er solution", autoSuggestParam.getTerm());
values.put(key, 50);
cnt++;
key = String.format("<span>%s</span>er purity", autoSuggestParam.getTerm());
values.put(key, 100);
cnt++;
}
if (cnt >= autoSuggestParam.getCount()) {
break;
}
}
autoSuggestResponse.setResponseDate(new Date().getTime());
return autoSuggestResponse;
}
The Response class:
public class AutoSuggestResponse {
private Long requestDate;
private Long responseDate;
private String version;
private String term;
private String language;
private Map<String, Map<String,Object>>autoSuggestions = new LinkedHashMap<String, Map<String,Object>>();
public Long getRequestDate() {
return requestDate;
}
public void setRequestDate(Long requestDate ) {
this.requestDate = requestDate;
}
public Long getResponseDate() {
return responseDate;
}
public void setResponseDate(Long responseDate) {
this.responseDate = responseDate;
}
public String getVersion() {
return version;
}
public void setVersion(String version) {
this.version = version;
}
public String getTerm() {
return term;
}
public void setLanguage(String language) {
this.language = language;
}
public String getLanguage() {
return language;
}
public void setTerm(String term) {
this.term = term;
}
public Map<String, Map<String,Object>>getAutoSuggestions() {
return autoSuggestions;
}
}
The web.xml
<display-name>MoxyAS</display-name>
<servlet>
<servlet-name>MoxyAutoSuggest</servlet-name>
<servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
<init-param>
<param-name>jersey.config.server.provider.packages</param-name>
<param-value>com.sial.search.ws</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
<servlet-mapping>
<servlet-name>MoxyAutoSuggest</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
</web-app>
By default EclipseLink JAXB (MOXy) will not marshal properties that only have a getter. You can add an #XmlElement annotation to have it become mapped:
#XmlElement
public Map<String, Map<String,Object>>getAutoSuggestions() {
return autoSuggestions;
}
By default MOXy does not use the map key as the JSON key. Below is a link to an example that explains how to set this up:
http://blog.bdoughan.com/2013/06/moxys-xmlvariablenode-using-maps-key-as.html
I figured out the problem. It had nothing to do with MOXy, adding the genson-0.98.jar to the path fixed the problem with the QueryParam not getting marshaled in the BeanParam.
Adding the #XmlElement to the resource did make Moxy work, sort of. If I add XmlElement to the Map in the Response Class I now get an error:
javax.servlet.ServletException: org.glassfish.jersey.server.ContainerException: java.lang.NoClassDefFoundError: org/eclipse/persistence/internal/libraries/asm/ClassWriter
But this is a new problem.

Deserialize JSON with Gson - Expected BEGIN_OBJECT but was String - Reddit's JSON

I'm trying to deserialize JSON from Reddit that you can obtain by appending .json to the url. An example would be:
http://www.reddit.com/r/pics/comments/1wvx52/.json?sort=top
However, I am getting the error message:
Exception in thread "main" com.google.gson.JsonSyntaxException: java.lang.IllegalStateException: Expected BEGIN_OBJECT but was STRING at line 1 column 9765
At line 1 column 9765 in the json there is the following code: "replies": "", whereas normally this would contain an object like this: replies: {
kind: "Listing",
data: {}
},
Does this mean that the json is a String when there is no data, but an object otherwise? How can I deserialize with gson properly if this is the case? I've included my classes below. I still need to figure out how to handle the json starting off with an array of basically two different objects (the first listing in the json is describing the link, while the second listing is describing the comments), but I'll cross that bridge when I get there. Thanks in advance if anyone can shed some light on this issue.
Main Class
public static void main(String[] args)
{
ArrayList<CommentsResults> commentsResults = new ArrayList<CommentsResults>();
String commentsURL = "http://www.reddit.com/r/pics/comments/1wvx52/.json?sort=top";
URL url = null;
try
{
url = new URL(commentsURL);
} catch (MalformedURLException ex)
{
System.out.println(ex.getMessage());
}
try
{
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(url.openStream()));
String jsonText = readAll(bufferedReader);
Gson gson = new GsonBuilder().create();
commentsResults = gson.fromJson(jsonText, new TypeToken<ArrayList<CommentsResults>>(){}.getType());
} catch (IOException ex)
{
System.out.println(ex.getMessage());
}
}
private static String readAll(Reader reader) throws IOException
{
StringBuilder stringBuilder = new StringBuilder();
int cp;
while ((cp = reader.read()) != -1)
{
stringBuilder.append((char) cp);
}
return stringBuilder.toString();
}
CommentsResults Class
public class CommentsResults {
private String kind;
private CommentsData data;
public CommentsResults()
{
}
public CommentsResults(String kind, CommentsData data)
{
this.kind = kind;
this.data = data;
}
public String getKind()
{
return kind;
}
public CommentsData getData()
{
return data;
}
public void setKind(String kind)
{
this.kind = kind;
}
public void setData(CommentsData data)
{
this.data = data;
}
}
CommentsData Class
private String modhash;
private List <CommentsChild> children;
public CommentsData()
{
}
public CommentsData(String modhash, List<CommentsChild> children)
{
this.modhash = modhash;
this.children = children;
}
public String getModhash()
{
return modhash;
}
public List<CommentsChild> getChildren()
{
return children;
}
public void setModhash(String modhash)
{
this.modhash = modhash;
}
public void setChildren(List<CommentsChild> children)
{
this.children = children;
}
CommentsChild Class
private String kind;
private Comment data;
public CommentsChild()
{
}
public CommentsChild(String kind, Comment comment)
{
this.kind = kind;
this.data = comment;
}
public String getKind()
{
return kind;
}
public Comment getComment()
{
return data;
}
public void setKind(String kind)
{
this.kind = kind;
}
public void setComment(Comment comment)
{
this.data = comment;
}
Comment Class
public class Comment {
private CommentsResults replies;
private String id;
private int gilded;
private String author;
private String parent_id;
private String body;
private int downs;
private String link_id;
private boolean score_hidden;
private int created_utc;
private String distinguished;
public Comment()
{
}
public Comment(CommentsResults replies, String id, int gilded, String author, String parent_id, String body, int downs, String link_id, boolean score_hidden, int created_utc, String distinguished)
{
this.replies = replies;
this.id = id;
this.gilded = gilded;
this.author = author;
this.parent_id = parent_id;
this.body = body;
this.downs = downs;
this.link_id = link_id;
this.score_hidden = score_hidden;
this.created_utc = created_utc;
this.distinguished = distinguished;
}
public CommentsResults getReplies()
{
return replies;
}
public String getId()
{
return id;
}
public int getGilded()
{
return gilded;
}
public String getAuthor()
{
return author;
}
public String getParent_id()
{
return parent_id;
}
public String getBody()
{
return body;
}
public int getDowns()
{
return downs;
}
public String getLink_id()
{
return link_id;
}
public boolean isScore_hidden()
{
return score_hidden;
}
public int getCreated_utc()
{
return created_utc;
}
public String getDistinguished()
{
return distinguished;
}
public void setReplies(CommentsResults replies)
{
this.replies = replies;
}
public void setId(String id)
{
this.id = id;
}
public void setGilded(int gilded)
{
this.gilded = gilded;
}
public void setAuthor(String author)
{
this.author = author;
}
public void setParent_id(String parent_id)
{
this.parent_id = parent_id;
}
public void setBody(String body)
{
this.body = body;
}
public void setDowns(int downs)
{
this.downs = downs;
}
public void setLink_id(String link_id)
{
this.link_id = link_id;
}
public void setScore_hidden(boolean score_hidden)
{
this.score_hidden = score_hidden;
}
public void setCreated_utc(int created_utc)
{
this.created_utc = created_utc;
}
public void setDistinguished(String distinguished)
{
this.distinguished = distinguished;
}
}
So in the off chance this helps somebody (which seems dubious at this point) I decided to parse the Json manually using recursion. Here's how I did it:
public static void getCommentsOnLink()
{
String commentsURL= "http://www.reddit.com/r/pics/comments/1wvx52/.json?sort=top";
URL url = null;
try
{
url = new URL(commentsURL);
} catch (MalformedURLException ex)
{
System.out.println(ex.getMessage());
}
String JsonText = readCommentJsonFromURL(url);
RedditCommentResults redditCommentResults = getCommentResults(JsonText);
}
private static String readCommentJsonFromURL(URL url)
{
String JSONText = null;
try
{
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(url.openStream()));
JSONText = readAll(bufferedReader);
} catch (IOException ex)
{
System.out.println(ex.getMessage());
}
return JSONText;
}
private static String readAll(Reader reader) throws IOException
{
StringBuilder stringBuilder = new StringBuilder();
int cp;
while ((cp = reader.read()) != -1)
{
stringBuilder.append((char) cp);
}
return stringBuilder.toString();
}
private static RedditCommentResults getCommentResults(String JsonText)
{
JsonParser parser = new JsonParser();
JsonArray completeJson = (JsonArray) parser.parse(JsonText);
//get link and comment object from the array containing an object for each
JsonObject linkParentJson = (JsonObject) completeJson.get(0);
JsonObject commentParentJson = (JsonObject) completeJson.get(1);
//use automatic deserializer for redditLink
JsonObject linkListingDataJson = linkParentJson.getAsJsonObject("data");
JsonObject linkChildrenJson = linkListingDataJson.getAsJsonArray("children").get(0).getAsJsonObject();
JsonObject linkDataJson = linkChildrenJson.getAsJsonObject("data");
Link commentLink = gson.fromJson(linkDataJson, Link.class);
RedditLink redditCommentLink = new RedditLink(commentLink);
//parse comments manually
JsonObject commentDataJson = commentParentJson.getAsJsonObject("data");
JsonArray commentChildrenJson = commentDataJson.getAsJsonArray("children");
//get all of the comments from the JsonArray
ArrayList<RedditComment> redditComments = getNestedComments(commentChildrenJson);
RedditCommentResults redditCommentResults = new RedditCommentResults(redditComments, redditCommentLink);
return redditCommentResults;
}
private static ArrayList<RedditComment> getNestedComments(JsonArray commentWrapperJsonArray)
{
ArrayList<RedditComment> redditComments = new ArrayList();
for (JsonElement commentWrapperJson : commentWrapperJsonArray)
{
//cast Element to Object so we can search for the primitive "kind". Finally we get it as a String
String kind = commentWrapperJson.getAsJsonObject().getAsJsonPrimitive("kind").getAsString();
//if the comment is of type t1 meaning it is a comment and not a "more" (a "more" is a comment which
//hasn't been loaded yet because it does not have a great deal of upvotes relative to other comments)
if (kind.equals("t1"))
{
JsonObject commentJson = commentWrapperJson.getAsJsonObject().getAsJsonObject("data");
Comment comment = gson.fromJson(commentJson, Comment.class);
RedditComment redditComment = new RedditComment(comment);
JsonElement repliesJson = commentJson.get("replies");
//if the reply is not equal to an empty String (i.e. if there is at least one reply)
if (!repliesJson.isJsonPrimitive())
{
JsonObject dataJson = repliesJson.getAsJsonObject().getAsJsonObject("data");
JsonArray childrenJson = dataJson.getAsJsonArray("children");
ArrayList<RedditComment> nestedComments = getNestedComments(childrenJson);
redditComment.setReplies(nestedComments);
}
redditComments.add(redditComment);
}
}
return redditComments;
}
You have to remove the private CommentsResults replies; from Comment Class and compose replies in CommentsChild class. According to Json fomate you model is
CommentResult -
CommentsData --
List <CommentsChild> children---
CommentsResults replies
recursion/ repeation of comment result
public class CommentsChild {
private String kind;
private Comment data;
//
private CommentsResults replies;
}