Categories
discuss

WeakReference not working in Kotlin

I’m implementing an AsyncTask in Kotlin, and I need a WeakReference for the callback that runs in the onPostExecute() method. I set the listener reference before calling execute(), but once onPostExecute() is called, the value of WeakReference is null.

class PhotoRotationTask(uri: Uri, filePath: String, resolver: ContentResolver) : AsyncTask<Int, Int, Int>() {
    private var weakRef : WeakReference<OnBitmapProcessedListener>? = null

    var sourceUri : Uri
    var resolver : ContentResolver
    var destPath: String

    init {
        this.sourceUri = uri
        this.resolver = resolver
        this.destPath = filePath
    }

    fun setOnBitmapProcessedListener(listener: OnBitmapProcessedListener){
        weakRef = WeakReference(listener)
        Log.d("RotationTask", "set listener ${weakRef?.get() != null}") //This Log proves that weakRef is initialized before onPostExecute()
    }

    override fun doInBackground(vararg params: Int?): Int? {
        //Bitmap processing, weakRef is never called in this function
    }

    override fun onPostExecute(result: Int?) {
        Log.d("RotationTask", "result: $result") //This log proves that onPostExecute() is called eventually
        weakRef!!.get()?.onBitmapProcessed() //This implies that weakRef is not null, because app never crashes, but onBitmapProcessed is not called, so the reference is gone.
    }

}

The listener variable modifies my activity’s UI, therefore it holds a reference to my activity. Activity is never recreated, my phone is still, never rotated or touched after AsyncTask starts. How is the WeakReference cleared??

Answer

The problem is in the WeakReference and local variable that you pass as listener.

WeakReference is known not to keep an object from being garbage collected, so if there’s no other reachable strong reference to it, it may be recycled at any moment once the method referencing it through local variable finishes. And this is exactly what happens in your case since the weak reference becomes null.

The solution is to store a strong reference to the object that is passed as listener somewhere in the calling code (as it uses the activity, the activity itself may store it in a property, so that the listener‘s lifetime would match that of the activity).

For example, declare a property

lateinit var currentListener: OnBitmapProcessedListener

in the activity code, then store the listener you create in that property:

val task = PhotoRotationTask(uri, filePath, resolver)

task.setOnBitmapProcessedListener(object : OnBitmapProcessedListener {
         // here goes the implementation
     }.apply { currentListener = this } // note this line
)

If multiple tasks and listeners are possible, then take care of storing all the listeners.

Categories
discuss

GWT Serialization – class has no instantiable subtypes

I’m trying to serialize this object (OperatorDTO) so I can use RPC to send it from my server side to client. I’ve read other posts on this topic but I don’t see why I’m doing anything diferent than other people.

When I’m running my project this error occurs

Compiling module edu.example.RPCExample
         Computing all possible rebind results for 'edu.example.client.service.ExampleService'
            Rebinding edu.example.client.service.ExampleService
               Invoking generator com.google.gwt.user.rebind.rpc.ServiceInterfaceProxyGenerator
                  Generating client proxy for remote service interface 'edu.example.client.service.ExampleService'
                     [ERROR] 'edu.example.client.models.OperatorDTO' has no instantiable subtypes
         [ERROR] Errors in 'edu/example/client/service/ExampleServiceClientImpl.java'
            [ERROR] Line 18: Failed to resolve 'edu.example.client.service.ExampleService' via deferred binding
         Unification traversed 16362 fields and methods and 1526 types. 1494 are considered part of the current module and 1494 had all of their fields and methods traversed.
      [ERROR] Compiler returned false
      [WARN] recompile failed
      [WARN] continuing to serve previous version

I don’t understand why I get the error “OperatorDTO has no instantiable subtypes” when I’ve implemented io.serializable and only use basic data types in the class. Is there something that I’m using in the class that is not allowed to when serializing it?

package edu.example.client.models;
import java.io.Serializable;

public final class OperatorDTO implements Serializable
{   
    private static final long serialVersionUID = 1L;
    private final int ID_MINIMUM_VALUE = 11;
    private final int ID_MAXIMUM_VALUE = 99;
    private final int RANK_MINIMUM_VALUE = -1;
    private final int RANK_MAXIMUM_VALUE = 1;
    private final int NAME_MINIMUM_LENGTH = 2;
    private final int PASSWORD_MINIMUM_LENGTH = 6;
    private final int NUMBER_OF_SPECIAL_CHARACTERS = 3;

    private int oprID;
    private String oprNavn;
    private String ini;
    private String cpr;
    private String password;
    private int rank;

public OperatorDTO(int oprID, String oprNavn, String ini, String cpr, String password, int rank) {
        setOprID(oprID);
        setName(oprNavn);
        setIni(ini);
        setCpr(cpr);
        setPassword(password);
        setRank(rank);
    }

    public OperatorDTO(int oprID, String oprNavn, String ini, String cpr, String password) {
        setOprID(oprID);
        setName(oprNavn);
        setIni(ini);
        setCpr(cpr);
        setPassword(password);
    }

    public void setIni(String ini) {
        this.ini = ini;
    }

    public String getIni() {
        return this.ini;
    }

    public void setRank(int rank) {
        if(rank >= RANK_MINIMUM_VALUE && rank <= RANK_MAXIMUM_VALUE)
            this.rank = rank;kravende");
    }

    public int getRank() {
        return this.rank;
    }

    public void setOprID(int oprID) {
        if(oprID >= ID_MINIMUM_VALUE && oprID <= ID_MAXIMUM_VALUE)
            this.oprID = oprID;
    }

    public int getOprID() {
        return this.oprID;
    }

    public void setName(String name) {
        if(name != null)
            if(name.length() >= NAME_MINIMUM_LENGTH)
                this.oprNavn = name;
    }

    public void setCpr(String cpr) {
        this.cpr = cpr;
    }

    public void setPassword(String password) {
        if(valPass(password))
            this.password = password;
    }

    public String getName() {
        return this.oprNavn;
    }

    public String getCpr() {
        return this.cpr;
    }

    public String getPassword() {
        return this.password;
    }

    private boolean valPass(String pass) {
        if(pass.length() < PASSWORD_MINIMUM_LENGTH)
            return false;

        byte lowerCase = 0;
        byte upperCase = 0;
        byte digit = 0;
        byte specialChar = 0;
        char[] passChar = pass.toCharArray();

        for (char c : passChar) {
            if(Character.isLowerCase(c)) 
                lowerCase = 1;
            else if(Character.isUpperCase(c))
                upperCase = 1;
            else if(Character.isDigit(c)) 
                digit = 1;
            else if(c == 46 || c == 45 || c == 95 || c == 43 || c ==33 || c == 63 || c == 61) 
                specialChar = 1;
            else 
                return false;
        }
        return (lowerCase + upperCase + digit + specialChar) >= NUMBER_OF_SPECIAL_CHARACTERS;
    }

    @Override
    public String toString() {
        return "OperatorDTO{" + "oprID=" + oprID + ", oprNavn=" + oprNavn + ", ini=" + ini + ", cpr=" + cpr + ", password=" + password + ", rank=" + rank + '}';
    }
}

Thanks for any help in advance!

Answer

GWT requires a default constructor.

see http://www.gwtproject.org/doc/latest/tutorial/RPC.html#serialize

Categories
discuss

Update By Query in Elasticsearch using Java

I’m currently using Elasticsearch V2.3.1. I want to use the following Elasticsearch query in Java.

POST /twitter/_update_by_query
{
  "script": {
    "inline": "ctx._source.List = [‘Item 1’,’Item 2’]”
  },
  "query": {
    "term": {
      "user": "kimchy"
    }
  }
}

The above query searches for “user” named “kimchy” and updates the “List” field with given values. This query updates multiple documents at the same time. I read about the Update API for Java here https://www.elastic.co/guide/en/elasticsearch/client/java-api/2.3/java-docs-update.html but couldn’t find what I was looking for. The Update API for Java only talks about updating single document at a time. Is there any way to update multiple documents? Sorry if I’m missing something obvious. Thank you for your time.

Update:

I tried the below Java Code:

Client client = TransportClient.builder().addPlugin(ReindexPlugin.class)
    .build().addTransportAddress(new InetSocketTransportAddress(
        InetAddress.getByName("127.0.0.1"), 9300));

UpdateByQueryRequestBuilder ubqrb = UpdateByQueryAction.INSTANCE
    .newRequestBuilder(client);

Script script = new Script("ctx._source.List = ["Item 1","Item 2"]");

//termQuery is not recognised by the program
BulkIndexByScrollResponse r = ubqrb.source("twitter").script(script)
    .filter(termQuery("user", "kimchy")).execute().get();

So I edited the Java Program as above and the termQuery is not identified by Java. May I know what I’m doing wrong here? Thanks.

Answer

As of ES 2.3, the update by query feature is available as the REST endpoint _update_by_query but nor for Java clients. In order to call this endpoint from your Java client code, you need to include the reindex module in your pom.xml, like this

<dependency>
    <groupId>org.elasticsearch.module</groupId>
    <artifactId>reindex</artifactId>
    <version>2.3.2</version>
</dependency>

Then you need to include this module when building your client:

clientBuilder.addPlugin(ReindexPlugin.class);

Finally you can call it like this:

UpdateByQueryRequestBuilder ubqrb = UpdateByQueryAction.INSTANCE.newRequestBuilder(client);

Script script = new Script("ctx._source.List = ["Item 1","Item 2"]");

BulkIndexByScrollResponse r = ubqrb.source("twitter")
    .script(script)
    .filter(termQuery("user", "kimchy"))
    .get();

UPDATE

If you need to specify the type(s) the update should focus on, you can do so:

ubqrb.source("twitter").source().setTypes("type1");
BulkIndexByScrollResponse r = ubqrb.script(script)
    .filter(termQuery("user", "kimchy"))
    .get();
Categories
discuss

Is it necessary to call close() in a finally when writing files in Java?

There are a few examples where people call close() in their finally block when writing to a file, like this:

OutputStream out = null;
try {
    out = new FileOutputStream(file);
    out.write(data);
    out.close();
}
catch (IOException e) {
    Log.e("Exception", "File write failed: " + e.toString());
} finally {
    try {
        if (out != null) {
            out.close();
        }
    } catch (IOException e) {
        Log.e("Exception", "File write failed: " + e.toString());
    }
}

But there are many more examples, including the official Android docs where they don’t do that:

try {
    OutputStream out = new FileOutputStream(file);
    out.write(data);
    out.close();
}
catch (IOException e) {
    Log.e("Exception", "File write failed: " + e.toString());
}

Given that the second example is much shorter, is it really necessary to call close() in finally as shown above or is there some mechanism that would clean up the file handle automatically?

Answer

Yes, it is. Unless you let someone else manage that for you.

Some solutions for that:

Categories
discuss

Splitting a string on whitespaces

I’m currently trying to splice a string into a multi-line string. The regex should select white-spaces which has 13 characters before.

The problem is that the 13 character count does not reset after the previous selected white-space. So, after the first 13 characters, the regex selects every white-space.

I’m using the following regex with a positive look-behind of 13 characters:

(?<=.{13}) 

(there is a whitespace at the end)

You can test the regex here and the following code:

import java.util.ArrayList;
public class HelloWorld{

     public static void main(String []args){
        String str = "This is a test. The app should break this string in substring on whitespaces after 13 characters";

        for (String string : str.split("(?<=.{13}) ")) {
            System.out.println(string);
        }
     }
}

The output of this code is as follows:

This is a test.
The
app
should
break
this
string
in
substring
on
whitespaces
after
13
characters

But it should be:

This is a test.
The app should
break this string
in substring on
whitespaces after
13 characters

Answer

You may actually use a lazy limiting quantifier to match the lines and then replace with $0n:

.{13,}?[ ]

See the regex demo

IDEONE demo:

String str = "This is a test. The app should break this string in substring on whitespaces after 13 characters"; 
System.out.println(str.replaceAll(".{13,}?[ ]", "$0n"));

Note that the pattern matches:

  • .{13,}? – any character that is not a newline (if you need to match any character, use DOTALL modifier, though I doubt you need it in the current scenario), 13 times at least, and it can match more characters but up to the first space encountered
  • [ ] – a literal space (a character class is redundant, but it helps visualize the pattern).

The replacement pattern – "$0n" – is re-inserting the whole matched value (it is stored in Group 0) and appends a newline after it.

Source: stackoverflow
Text is available under the Creative Commons Attribution-ShareAlike License; additional terms may apply. By using this site, you agree to the Privacy Policy, and Copyright Policy. Content is available under CC BY-SA 3.0 unless otherwise noted. The answers/resolutions are collected from stackoverflow, are licensed under cc by-sa 2.5 , cc by-sa 3.0 and cc by-sa 4.0 © No Copyrights, All Questions are retrived from public domain..