Because we're passing object to Spring Framework in which Jackson classes convert them into JSON as a response, we chose to implement a simpler Tweet class rather than the Twitter4j-provided Status class, which includes numerous data that is irrelevant.

Status class provided by Twitter4j has arrays of entities that specify start and end indices of the entity in the body text.

For example:

Hello @fuxximus, how are you?

The tweet will have an entity @fuxximus with indices: start 6 end 15. So having multiple entities and inserting tags around them makes any index after the inserted shifted by the number of chars of the inserted tag/string. I don't think the entities are sorted in the order of their appearance, and even so it wouldn't matter because there are different types of entities.

So to account to that I came up with a simple HashMap that registers all indices and their added string length as they're entered, then when inserting every next insertion it calculates its new offset if change to it has been made from the HashMap.

Note: the tags will be more dynamic in the future, so the length of the tag will be variable.

Is there a more elegant way of solving this than using HashMap and looping through it every single entity? I couldn't come up with anything else.

package com.univision.proxy.data.twitter;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;

import twitter4j.HashtagEntity;
import twitter4j.MediaEntity;
import twitter4j.Status;
import twitter4j.URLEntity;
import twitter4j.UserMentionEntity;

public class Tweet {
    public String name;
    public String screenname;
    public Date time;
    public String body;
    public Boolean is_retweet = false;
    public String original_name = null;
    public String original_screenname = null;
    public Date original_time = null;
    public long original_id = 0;
    public long id;
    public Tweet(Status stat){
            this.is_retweet = true;
            this.original_name = stat.getUser().getName();
            this.original_screenname = stat.getUser().getScreenName();
            this.original_time = stat.getCreatedAt();
            this.original_id = stat.getId();
            stat = stat.getRetweetedStatus();
        this.name = stat.getUser().getName();
        this.screenname = stat.getUser().getScreenName();
        this.time = stat.getCreatedAt();
        this.id = stat.getId();

        this.body = ParseTweetText(stat);

    public static String ParseTweetText(Status stat)    {
        StringBuffer body = new StringBuffer(stat.getText());
        HashMap<Integer,Integer> paddings = new HashMap<Integer,Integer>();

        HashtagEntity[] hashtags = stat.getHashtagEntities();
        MediaEntity[] medias = stat.getMediaEntities();
        URLEntity[] urls = stat.getURLEntities();
        UserMentionEntity[] users = stat.getUserMentionEntities();

        String tag = "";
        for(HashtagEntity hashtag : hashtags){
            tag = "<span class=\"link\">";
            body.insert(CalculateOffset(paddings, hashtag.getStart()), tag);
            paddings.put(hashtag.getStart(), tag.length());
            tag = "</span>";
            body.insert(CalculateOffset(paddings, hashtag.getEnd()), tag);
            paddings.put(hashtag.getEnd(), tag.length());
        for(MediaEntity media : medias){
            tag = "<span class=\"link\">";
            body.insert(CalculateOffset(paddings, media.getStart()), tag);
            paddings.put(media.getStart(), tag.length());
            tag = "</span>";
            body.insert(CalculateOffset(paddings, media.getEnd()), tag);
            paddings.put(media.getEnd(), tag.length());
        for(URLEntity url : urls){
            tag = "<span class=\"link\">";
            body.insert(CalculateOffset(paddings, url.getStart()), tag);
            paddings.put(url.getStart(), tag.length());
            tag = "</span>";
            body.insert(CalculateOffset(paddings, url.getEnd()), tag);
            paddings.put(url.getEnd(), tag.length());
        for(UserMentionEntity user : users){
            tag = "<span class=\"link\">";
            body.insert(CalculateOffset(paddings, user.getStart()), tag);
            paddings.put(user.getStart(), tag.length());
            tag = "</span>";
            body.insert(CalculateOffset(paddings, user.getEnd()), tag);
            paddings.put(user.getEnd(), tag.length());

        return body.toString();

    public static int CalculateOffset(HashMap<Integer,Integer> indices, int index)  {
        int ret_val = index;
        for (Map.Entry<Integer, Integer> entry : indices.entrySet()) {
            if(index > entry.getKey()){
                ret_val += entry.getValue();
        return ret_val;

1 Answer 1


If the interfaces HashtagEntity, MediaEntity, URLEntity, and UserMentionEntity were subinterfaces of a superinterface Entity, you could refactor the 4 loops into 4 calls to one function that would take Entity[] as one of the parameters, although with the Java inability to pass byref, I'm not sure it would be that good.

  • \$\begingroup\$ I checked twitter4j docs those 4 did not share any common class as you said. It would have been nice though. Wait.... i think i missed something. \$\endgroup\$
    – ochitos
    Mar 14, 2013 at 1:40
  • \$\begingroup\$ Only URLEntity extends MediaEntity, and all 4 only have java.io.Serializable as a superinterface. \$\endgroup\$
    – ochitos
    Mar 14, 2013 at 1:45
  • \$\begingroup\$ Yes, that's why I said "If". It looks like you are already messing with the source code by replacing the provided Tweet class with your own. You can create the Entity interface yourself and make the other interface become subinterfaces of the Entity one. \$\endgroup\$ Mar 15, 2013 at 15:52

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.