Friday, August 31, 2018

WSSE - XML SOAP security and key encryption and storing (EncryptedData/EncryptedKey)

Leave a Comment

I have now spent the last couple of days to find documentation about this..

I need to send a XML via SOAP with the WSSE security header, but don't know how to encrypt and store the encrypted keys

Here is an example

<?xml version="1.0" encoding="UTF-8" standalone="no"?> <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">     <soap:Header>         <wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" soap:mustUnderstand="1">             <xenc:EncryptedKey xmlns:xenc="http://www.w3.org/2001/04/xmlenc#" Id="EK-1B758D26C51BFCD86614340101135741">                 <xenc:EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p"/>                 <ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#">                     <wsse:SecurityTokenReference>                         <wsse:KeyIdentifier EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary" ValueType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3">MIIDODCCAiCgAwIBAgIGAU0FlCVCMA0GCSqGSIb3DQEBCwUAMFoxCzAJBgNVBAYTAkRLMRUwEwYDVQQKEwxCYW5rIENvbm5lY3QxFTATBgNVBAsTDEJhbmsgQ29ubmVjdDEdMBsGA1UEAxMUQmFuayBDb25uZWN0IElBLXRlc3QwHhcNMTUwNDI5MTQyODI0WhcNMTgwNDI5MTQyODI0WjAcMRowGAYDVQQDExFiYW5rIGNvbm5lY3QtdGVzdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAI23KdtaRKPTFTe/A1PnsF9dpSlTiXurKmio0OCgTP9wClHwync3JsInRwGTooA20P9zWobUnEFbEiAgRVYCxuYoldRE6NLhSC854/YTjMBeevH1TNa38lpavGiI4UwFhg70U9/JuYs21hoFyzVfaWlVfOkAMm1U/n4wHq6FZW461S5PY4A/UI1Mr8WgeIHU9GqMBtFvjynzq3SLenOPgdmKtyJ3V8EOU+DlgwKmDbxMVMtYNDZtoQvOWnuvlJ6ICDcqcW7OUkmwCKodjxxPvrdaPxyZDhT7h4FgRtrAOS8qR6L7x9D4ZIoxOMPudGvr99OSb4KVtaAEt/R7hKxG3OsCAwEAAaNCMEAwHwYDVR0jBBgwFoAU680YSkZnx1IaJAmI49LlTGiia0wwHQYDVR0OBBYEFMaWOY7Vf/iB3WVA96j5kRtbF8prMA0GCSqGSIb3DQEBCwUAA4IBAQAJ+bssSFWE6KsYT7HSDKag4Eot7yNGMY4Don/MilDnOREdu20QUS131DKrSkpBQiCXbyRUQjUoun4yue0EG+rlG3QUIlNNdJ4KZJB+dTYdLUV7XTYJNPimKAmoZ+PFNvT1eGgWcMT+MbTfpk0mw0V8IprYGa8UPchd6vtSVwpbTcPc/F4bgUTlm/V+FG4bQS61gF0koj0DEZjzat7CBHpozRgfRlXgwu26vnhWGc99uKH4GAKN4JpqPi/6Yz+7iQNJUC3yeezgBxFrIXuLpkBZSP4zunf9VxsICnxkFUXOTuYBdcbhPNzqMknD5ijFcFRZITwdv7x3uJGLkM7iUfBp</wsse:KeyIdentifier>                     </wsse:SecurityTokenReference>                 </ds:KeyInfo>                 <xenc:CipherData>                     <xenc:CipherValue>af9+FhA91ytLwjeRvTYJsRCkhjHmAQGwqYwMBoNZBn7BZhF/a6EUpM9ByarVhx1SRCpjW5fb8tBVuJO1ZkjfTUZ5EAh/oDLbkmwPdSAAVzmAURHwCq3XQgMZV3lAczlLnPamxjjZBCGqxvAmBo1CvFFPC4AcBedqY92mP8XGyVHpS7JYKOxqXK2vUA1by7371x+Mu0aoS2zJPyPLa1IPwOYgR9qicmWz1RNPiEVA8ZBCN0NRyg7FLJxdUcE81z+1SjButBo2j3qcwkNcecHzZAnweY+LSWp3H5JA3WNzUHUuvFHEaPzT5jd7fUI16xo8NLK8/Rd8Eq/zDD+T3baeVQ==</xenc:CipherValue>                 </xenc:CipherData>                 <xenc:ReferenceList>                     <xenc:DataReference URI="#ED-1B758D26C51BFCD86614340101135852"/>                 </xenc:ReferenceList>             </xenc:EncryptedKey>         </wsse:Security>         <technicalAddress xmlns="http://example.com/schema/2014" xmlns:ns2="http://www.w3.org/2000/09/xmldsig#"/>         <activationHeader xmlns="http://example.com/schema/2014" xmlns:ns2="http://www.w3.org/2000/09/xmldsig#">             <organisationIdentification>                 <mainRegistrationNumber>8079</mainRegistrationNumber>                 <isoCountryCode>DK</isoCountryCode>             </organisationIdentification>             <functionIdentification>112233445566778899</functionIdentification>             <erpInformation/>             <endToEndMessageId>d28b6a7dad414014a59029ef1a7e84d4</endToEndMessageId>             <createDateTime>2015-06-11T10:08:33.258+02:00</createDateTime>         </activationHeader>     </soap:Header>     <soap:Body>         <xenc:EncryptedData xmlns:xenc="http://www.w3.org/2001/04/xmlenc#" Id="ED-1B758D26C51BFCD86614340101135852" Type="http://www.w3.org/2001/04/xmlenc#Content">             <xenc:EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#aes256-cbc"/>             <ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#">                 <wsse:SecurityTokenReference xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" xmlns:wsse11="http://docs.oasis-open.org/wss/oasis-wss-wssecurity-secext-1.1.xsd" wsse11:TokenType="http://docs.oasis-open.org/wss/oasis-wss-soap-message-security-1.1#EncryptedKey">                     <wsse:Reference URI="#EK-1B758D26C51BFCD86614340101135741"/>                 </wsse:SecurityTokenReference>             </ds:KeyInfo>             <xenc:CipherData>                 <xenc:CipherValue>dTSVuEJ90OYguQOsOz2ZtcE2mybwuvVl19pp7/e5yuvNygx3w5v+prpEvbjYLauiIAB3lrVDK2astJeYJGnDbaVJVeU0YqH5ItYVn7Wz36jJM52KB+UNbYo8EdTKYjsZuADzH+tAoA+pwYxGBXMEQctNI+C711HgP2hbpHNYOG7nAMOIrP/0B3FCy+st+9CbYlwAEENreTYunEEA41hciFnWCsIx0el7OeuiA6V51fAmvrF19RPNKwaptvbvmVdKj//RQ/0U1kRny16mDnFfX92bI3HBQm4XJA0nEfSvio7EUAAdhe77GMfu7+JELqXNowPGPLlvrbCFYnQhxGRITHtTIEbtJA6MKtBzHgjtw5pt7oWxKgGUnaJTfOPOSv43RLFGggkT/+gTjnZOagu8hhXp0x5HXJuZzw90aIS3jAfSPDc2ivct4WhWk0wcuQyC2rAh4I7gtiR+LqJJGqvucw4S+NR95FunKHKEW4yasKW1oU31/rRbp4Bmwo6BPsQlxnaSHPtk68IVkYDBslz1A5gOP+M/Iam2WI02y6sE/7aAH1ruN3pZlVuYFc3JDNHOPOvevP110d60lroknGdc9vxcFfj48OCKw/8Ed6tiXtAvk0Qu9Qt4ZyLUoPKIWEqjdLjwVadTDJQFAxRptNgiCos7s0czadUu7FNCRxfndjDxhA7trvys44ufEyK++YzZIgNu3r4dywNI22Nm+JZtLj+rX8ARE6FTPlxGBD0SSdXsfCfY2N1ytBBHQRnPsVaHK1p7KOhwQVbqEupcGyvaRolnymOzDLGFdS06OGYFrYXdgIbuqYtZP8QerXtUl0sWNAvvqHSPCQcpKecpMEecar+FUVwLEA+H1wzOprCMbRR+EgIboeDqQ7GxXqugkuFyvnlLDgxnaWhEhQb/5kAcQmnyUZ57MhDcUJqqQ4Cdmwrcxho1P+YqWY9yn0E86F+hl5976a/gH5KBobB84OWmgcX42eAmqpJf+8c8SuBv+7NctbQOk21aYlFEpkwSme/kG1/edtyoHQH/hF0RB1cT8g+u9S9AK2rs3s2G+Ap0U5oyY8pqJalGdZSBudE0sU4mhOV8trtx0FrN9A7pNkTcGPH25nCtyIz6rzR+DP8Mtgw5385s5ivVlDb+z74Wbh6iu7ZkVAogNTpUYU/1BxDXWJqFMkFmfziNxQ5AQqm1vGlBzXifoQkUFX1riutNphmu0Hs+7KMmMLvtW2cXmQDpkHFKVheeN4w7pBCEZ8KhZ0VTOwRZcdvrNcpYfXM13/QdTHQmCqqwgS/VvlUFz7PDn0/OKo6moUic8W6b1iEvd3kfc7QkunxoOUoJr4RwJ+PqCzN6PxQivAFA2tmDPc8qEa1PAdxTeNFoR/6dNQRojouuJq3C1LrbmGf6lQPvKi3KeKHXyjmDr7Tve+al2tcWJVr+1qEM3/XuthoiZbuTDxYUjZ2nf2fhHrmNcfvrfNxSNHVdQPp2R9Rf3eGxlRJsmRpef66VbYhOpmiH4xmq45EWiyBZmYm+tZtjsP51EDMIvdFbVRSGO/hMqURrDSsJXJeot27Iup2s0P2n/6a9k0c4SVvf/WXNN5x9JNvjU97bQNDQRfonJmo9pRYYHl1tSqNIYBK7KsMH+qr1vmiJuhrXUuL/RtOKvE9KXQ8kGoC9oF5rFn21z40ElxG5XRTASg==</xenc:CipherValue>             </xenc:CipherData>         </xenc:EncryptedData>     </soap:Body> </soap:Envelope> 

First of all I have never worked with SOAP before so chances I do things wrong has pretty good odds :)

The body of the SOAP request is encrypted with AES-256-CBC, a 16 char random-generated iv and a 16 char random-generated key. My first problem is how the symmetric key is stored in the security header?

Have found something here, but I need more details https://www.w3.org/TR/2002/REC-xmlenc-core-20021210/Overview.html#aes256-cbc

How are the iv and the key stored in CipherValue in the header?

When sending the XML request to the webservice I get this error

23-08-2018 12:50:02   General exception:Padding is invalid and cannot be removed. 23-08-2018 12:50:02   Stack trace:    at System.Security.Cryptography.CapiSymmetricAlgorithm.DepadBlock(Byte[] block, Int32 offset, Int32 count)    at System.Security.Cryptography.CapiSymmetricAlgorithm.TransformFinalBlock(Byte[] inputBuffer, Int32 inputOffset, Int32 inputCount)    at System.Security.Cryptography.Xml.EncryptedXml.DecryptData(EncryptedData encryptedData, SymmetricAlgorithm symmetricAlgorithm)    at SomeClassCore.XmlSecurity.Decryptor.DecryptData(Byte[] symmetricKey)    at SomeClassCore.SecurityServiceImpl.UnwrapRequest(ServiceRequest serviceRequest)    at BD.BCA.MessageHandler.MessageHandler.ProcessRequest(HttpContext context) 

The way I store the symmetric key is like this

$key_length = 16; $cipher     = 'AES-256-CBC';  $iv     = openssl_random_pseudo_bytes(openssl_cipher_iv_length($cipher)); $key    = openssl_random_pseudo_bytes($key_length);  // Encryption of the body $encrypted_body = openssl_encrypt($body, $cipher, $key, 0, $iv);  // length 32 chars $symmetric_key = $iv.$key;  // The symmetric key is then encrypted via RSA and the public key.. $public_cert = openssl_pkey_get_public('the public cert'); openssl_public_encrypt($symmetric_key, $encrypted_key, $public_cert, OPENSSL_PKCS1_OAEP_PADDING);  // encrypted key is put in header EncryptedKey $encrypted_key;  // encrypted body is put in EncryptedData $encrypted_body; 

The part with the RSA encryption/decryption seems to work according to the error log right? It fails when decrypting the AES right?

This is how the symmetric key, and the iv and key alone looks like when dumping them with var_dump

symmetric key (not encrypted): string(32) "��J�    v��rb։�3�U���_$6p9�;p" iv: string(16) "��J�    v��rb։�" key: string(16) "3�U���_$6p9�;p" 

Symmetric key (base64 and not encrypted): 1/hKgBsfCXaUn3IaYtaJyzP0EFXK0uJfJDZwOR3AO3A=

update

Have searched a bit more.. Maybe the iv must be a part of the stored data. But it's still not working? Same error as above

class Encryption {     public function data_encrypt(string $data, string $cipher, int $key_length): Array{         $iv     = openssl_random_pseudo_bytes(openssl_cipher_iv_length($cipher));         $key    = openssl_random_pseudo_bytes($key_length);          return [             'data'  => base64_encode($iv.openssl_encrypt($data, $cipher, $key, OPENSSL_RAW_DATA, $iv)),             'key'   => $key         ];     }      public function key_encrypt(string $key): string{         $public_cert = openssl_pkey_get_public('contents of public cert');         openssl_public_encrypt($key, $data, $public_cert, OPENSSL_PKCS1_OAEP_PADDING);         openssl_free_key($public_cert);          return base64_encode($data);     } }  $Enc = new Encryption; $data_encrypted = $Env->data_encrypt('The message I want to encrypt', 'AES-256-CBC', 32);  //  This base64 encoded string goes to <EncryptedData> $data_encrypted['data'];  //  This base64 encoded string goes to <EncryptedKey> in the header $Enc->key_encrypt($data_encrypted['key']); 

0 Answers

Read More

large Navigation Bar backGround gets clear color when swiping back to root viewController

Leave a Comment

Hey guys i've used largeNavigationBar and it's ok until i swipe back to root view controller and large navigation gets clear color in a nasty way. here's the code:

func largeNavigationTitle() {      self.navigationController?.view.backgroundColor = VVUtility.navigationBarColor()     let productTitle = request?.product?.name     self.navigationItem.title = "\(productTitle ?? " ")".localized()     self.navigationController?.navigationBar.titleTextAttributes = [NSAttributedStringKey.foregroundColor : UIColor.white, NSAttributedStringKey.font : VVUtility.normalFontWithPlusSize(increaseSize: -2.0)]      if #available(iOS 11.0, *) {         self.navigationController?.navigationBar.prefersLargeTitles = true         self.navigationController?.navigationBar.backgroundColor = VVUtility.splashBackGroundColor()         self.navigationController?.navigationBar.largeTitleTextAttributes = [NSAttributedStringKey.foregroundColor : UIColor.white, NSAttributedStringKey.font : VVUtility.normalFontWithPlusSize(increaseSize: 0.0)]     } else {         // Fallback on earlier versions     }  } 

I've recalled largeNavigationTitle() in both viewWillAppear and viewDidLoad

UPDATE

here is screenshot of two states: before swiping: imgur.com/a/ZcSOrov when swiping: imgur.com/a/DYeeot8

4 Answers

Answers 1

Did you try this in your code ?

self.navigationController.navigationBar.translucent = NO; 

Answers 2

This is actually your navigation bar changing back to the small bar mode on the bottom controller.

This is because your navigation bar is not translucent. This causes (by default) the content controller to stop at the bottom of the navigation bar. So when the navigation bar becomes small again, there is no content between its new, shorter bottom and the top of the view controller.

Your hierarchy will look like this:

image

Now there's a property on UIViewController that defaults to false. You can use it to specify that you want your controller's view to extend under the non-translucent bar:

extendedLayoutIncludesOpaqueBars = true

This instantly makes the hierarchy now appear as:

image2

Now you should no longer get the gap - but you might have issues with UI elements going under the bar. You can handle that by using Safe area insets and tweaking your layout as needed, using edgesForExtendedLayout may also help depending on your layout.

TL;DR Use extendedLayoutIncludesOpaqueBars = true

Answers 3

Try this. It should set your root View controller's navigationBar's colour to the one you wanted:

func largeNavigationTitle() {      self.navigationController?.view.backgroundColor = VVUtility.navigationBarColor()    //add the two lines below     self.navigationController?.navigationBar.barTintColor = VVUtility.navigationBarColor()     self.navigationController?.navigationBar.isTranslucent = false      let productTitle = request?.product?.name     self.navigationItem.title = "\(productTitle ?? " ")".localized()     self.navigationController?.navigationBar.titleTextAttributes = [NSAttributedStringKey.foregroundColor : UIColor.white, NSAttributedStringKey.font : VVUtility.normalFontWithPlusSize(increaseSize: -2.0)]      if #available(iOS 11.0, *) {         self.navigationController?.navigationBar.prefersLargeTitles = true         self.navigationController?.navigationBar.backgroundColor = VVUtility.splashBackGroundColor()         self.navigationController?.navigationBar.largeTitleTextAttributes = [NSAttributedStringKey.foregroundColor : UIColor.white, NSAttributedStringKey.font : VVUtility.normalFontWithPlusSize(increaseSize: 0.0)]     } else {         // Fallback on earlier versions     }  } 

Answers 4

Please try to call method in AppDelegate.swift

       func application(_ application: UIApplication,             willFinishLaunchingWithOptions launchOptions:        [UIApplicationLaunchOptionsKey: Any]?) -> Bool {              } 
Read More

Why can't load js file in my local apache2 server?

Leave a Comment

In my local domain's webpage , both
jq.src = "https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.js";
jq.src = http://127.0.0.1/js/jquery-3.3.1.min.js
can be loaded.

In the stackoverflow's webpage,right click to enter into chrome's inspect--console.

const jq = document.createElement('script'); jq.src = "https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.js"; document.head.appendChild(jq); jq.addEventListener('load', () => {   console.log("hello world");   console.log($ === jQuery); }); 

The remote jquery.js file can be loaded,now to replace it with local js file--http://127.0.0.1/js/jquery-3.3.1.min.js .
Why can't load the js file in my local apache2?

enter image description here

2 Answers

Answers 1

Sites you are visiting can apply security policy for javascript - which includes the debugger. I think what you are seeing is the application of the content security policy associated with the web page you are visiting.

You can see this in the page headers. In Chrome (as explained here), you can view the html headers sent with the page:

Open the developer panel, select the "network" tab, and reload the page.

For stackoverflow, look under the "name" column for "stackoverflow.com" - there may be two if you originally loaded it via http, so find the one which is https - probably the second one. Click that one, and select the "headers" tab on the right. You will see in amongst the response headers:

content-security-policy: upgrade-insecure-requests 

This is explained here.

Basically, it tells the browser that all http requests should be "upgraded" to https. So when you try to access http://127.0.0.1/..., your browser upgrades the request to https://127.0.0.1/..., which your local server probably isn't set up to handle.

This is not limited to Chrome - all modern browsers should do this.

I browsed, for example, a few sites with Safari, and, in some cases, got an error message, such as on GitHub:

Refused to load https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.js because it does not appear in the script-src directive of the Content Security Policy. 

That is another variety of content security policies you can read about here.

Answers 2

try jq.setAttribute('src',"https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.js"); jq.setAttribute('crossOrigin',"Anonymos") jq.onload=onFinish;

Read More

URL requested a HTTP redirect, but it could not be followed. - Facebook/Nginx issue

Leave a Comment

I have used Facebooks sharing debugger to highlight an issue on the website

URL requested a HTTP redirect, but it could not be followed. 

https://developers.facebook.com/tools/debug/sharing/?q=https%3A%2F%2Fwww.badgerbookings.com

This is also stopping it accepting the url in the privacy policy when creating an app. enter image description here

I have researched and made sure to add all OG meta tags. I also "reduced" down the redirects on my nginx to only support a http > https redirect which to me seems pretty standard.

It still produces the error on both the debugger and the Privacy Policy URL.

My Nginx config:

server_tokens off; #Enables or disables emitting nginx version on error pages and in the “Server” response header field  map $http_upgrade $connection_upgrade {         default upgrade;         '' close; }  server {     listen 80;     server_name _;     return 301 https://www.badgerbookings.com$request_uri; }  server {         server_name www.badgerbookings.com  badgerbookings.com *.badgerbookings.com;          location / {             proxy_pass http://localhost:3000;                 proxy_http_version 1.1;                 proxy_set_header Upgrade $http_upgrade; # allow websockets                 proxy_set_header Connection $connection_upgrade;                 proxy_set_header X-Forwarded-For $remote_addr; # preserve client IP                 proxy_set_header Host $http_host;                 proxy_set_header X-Forward-Proto http;                 proxy_set_header X-Nginx-Proxy true;          }      listen 443 ssl; # managed by Certbot     ssl_certificate /etc/letsencrypt/live/badgerbookings.com-0001/fullchain.pem; # managed by Certbot     ssl_certificate_key /etc/letsencrypt/live/badgerbookings.com-0001/privkey.pem; # managed by Certbot     include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot     ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot  } 

2 Answers

Answers 1

Go to Facebook Developer's policy page.

Scroll down to this bit:

Privacy Policy

a. Provide a publicly available and easily accessible privacy policy that explains what data you are collecting and how you will use that data.

Now run

curl https://badgerbookings.com/terms

Are you looking at an easily accessible privacy policy which is publicly available at that url?

Answers 2

You maybe having IPv6 issues which can be resolved as simple as adding a listen [::]:443 ssl directive in you SSL server block.

If that doesn't fix it, try redirecting with a matching if directive

if ($scheme != "https") {     return 301 https://www.badgerbookings.com$request_uri } 

This is best if you unite both server blocks in one, to avoid more code. Just delete the non-https one and insert port 80 listen directives on the other one as well, with that conditional redirect, this way your code will be even slimmer.

Read More

How to correctly invalidate layout for supplementary views in UICollectionView

Leave a Comment

I am having a dataset displayed in a UICollectionView. The dataset is split into sections and each section has a header. Further, each cell has a detail view underneath it that is expanded when the cell is clicked.

For reference:

enter image description here

For simplicity, I have implemented the details cells as standard cells that are hidden (height: 0) by default and when the non-detail cell is clicked, the height is set to non-zero value. The cells are updates using invalidateItems(at indexPaths: [IndexPath]) instead of reloading cells in performBatchUpdates(_ updates: (() -> Void)?, completion: ((Bool) -> Void)? = nil) as the animations seems glitchy otherwise.

Now to the problem, the invalidateItems function obviously updates only cells, not supplementary views like the section header and therefore calling only this function will result in overflowing the section header:

enter image description here

After some time Googling, I found out that in order to update also the supplementary views, one has to call invalidateSupplementaryElements(ofKind elementKind: String, at indexPaths: [IndexPath]). This might recalculate the section header's bounds correctly, however results in the content not appearing:

enter image description here

This is most likely caused due to the fact that the func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView does not seem to be called.

I would be extremely grateful if somebody could tell me how to correctly invalidate supplementary views to the issues above do not happen.

Code:

   override func numberOfSections(in collectionView: UICollectionView) -> Int {         return dataManager.getSectionCount()     }      override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {         let count = dataManager.getSectionItemCount(section: section)         reminder = count % itemsPerWidth         return count * 2     }      override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {          if isDetailCell(indexPath: indexPath) {             let cell = collectionView.dequeueReusableCell(withReuseIdentifier: Reusable.CELL_SERVICE, for: indexPath) as! ServiceCollectionViewCell             cell.lblName.text = "Americano detail"              cell.layer.borderWidth = 0.5             cell.layer.borderColor = UIColor(hexString: "#999999").cgColor             return cell          } else {             let item = indexPath.item > itemsPerWidth ? indexPath.item - (((indexPath.item / itemsPerWidth) / 2) * itemsPerWidth) : indexPath.item             let product = dataManager.getItem(index: item, section: indexPath.section)              let cell = collectionView.dequeueReusableCell(withReuseIdentifier: Reusable.CELL_SERVICE, for: indexPath) as! ServiceCollectionViewCell             cell.lblName.text = product.name              cell.layer.borderWidth = 0.5             cell.layer.borderColor = UIColor(hexString: "#999999").cgColor              return cell         }     }      override func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView {         switch kind {         case UICollectionElementKindSectionHeader:             if indexPath.section == 0 {                 let header = collectionView.dequeueReusableSupplementaryView(ofKind: UICollectionElementKindSectionHeader, withReuseIdentifier: Reusable.CELL_SERVICE_HEADER_ROOT, for: indexPath) as! ServiceCollectionViewHeaderRoot                 header.lblCategoryName.text = "Section Header"                 header.imgCategoryBackground.af_imageDownloader = imageDownloader                 header.imgCategoryBackground.af_setImage(withURLRequest: ImageHelper.getURL(file: category.backgroundFile!))                 return header             } else {                 let header = collectionView.dequeueReusableSupplementaryView(ofKind: UICollectionElementKindSectionHeader, withReuseIdentifier: Reusable.CELL_SERVICE_HEADER, for: indexPath) as! ServiceCollectionViewHeader                 header.lblCategoryName.text = "Section Header"                 return header             }         default:             assert(false, "Unexpected element kind")         }     }      // MARK: UICollectionViewDelegate      func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {         let width = collectionView.frame.size.width / CGFloat(itemsPerWidth)          if isDetailCell(indexPath: indexPath) {             if expandedCell == indexPath {                 return CGSize(width: collectionView.frame.size.width, height: width)             } else {                 return CGSize(width: collectionView.frame.size.width, height: 0)             }         } else {             return CGSize(width: width, height: width)         }     }      func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForHeaderInSection section: Int) -> CGSize {         if section == 0 {             return CGSize(width: collectionView.frame.width, height: collectionView.frame.height / 3)         } else {             return CGSize(width: collectionView.frame.width, height: heightHeader)         }     }      override func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {         if isDetailCell(indexPath: indexPath) {             return         }          var offset = itemsPerWidth         if isLastRow(indexPath: indexPath) {             offset = reminder         }          let detailPath = IndexPath(item: indexPath.item + offset, section: indexPath.section)         let context = UICollectionViewFlowLayoutInvalidationContext()          let maxItem = collectionView.numberOfItems(inSection: 0) - 1         var minItem = detailPath.item         if let expandedCell = expandedCell {             minItem = min(minItem, expandedCell.item)         }          // TODO: optimize this         var cellIndexPaths = (0 ... maxItem).map { IndexPath(item: $0, section: 0) }          var supplementaryIndexPaths = (0..<collectionView.numberOfSections).map { IndexPath(item: 0, section: $0)}          for i in indexPath.section..<collectionView.numberOfSections {             cellIndexPaths.append(contentsOf: (0 ... collectionView.numberOfItems(inSection: i) - 1).map { IndexPath(item: $0, section: i) })             //supplementaryIndexPaths.append(IndexPath(item: 0, section: i))         }          context.invalidateSupplementaryElements(ofKind: UICollectionElementKindSectionHeader, at: supplementaryIndexPaths)         context.invalidateItems(at: cellIndexPaths)          if detailPath == expandedCell {             expandedCell = nil         } else {             expandedCell = detailPath         }          UIView.animate(withDuration: 0.25) {             collectionView.collectionViewLayout.invalidateLayout(with: context)             collectionView.layoutIfNeeded()         }     } 

1 Answers

Answers 1

If you call your collectionView.layoutIfNeeded() within your animate function the animation doesn't work. I suggest you reload the collectionView as you should have invalidated the supplement views it should give you the required results. If however that will not work then you can try adding a couple of print statements to see if the invalidatedSupplementViews are registered correctly.

// TODO: optimize this     var cellIndexPaths = (0 ... maxItem).map { IndexPath(item: $0, section: 0) }      var supplementaryIndexPaths = (0..<collectionView.numberOfSections).map { IndexPath(item: 0, section: $0)}      for i in indexPath.section..<collectionView.numberOfSections {         cellIndexPaths.append(contentsOf: (0 ... collectionView.numberOfItems(inSection: i) - 1).map { IndexPath(item: $0, section: i) })         //supplementaryIndexPaths.append(IndexPath(item: 0, section: i))     }      context.invalidateSupplementaryElements(ofKind: UICollectionElementKindSectionHeader, at: supplementaryIndexPaths)     context.invalidateItems(at: cellIndexPaths)     print("____________INFO________________")     print("THE SUPPLEMENTARY INDEX PATHS ARE: \(supplementaryIndexPaths))"     print("------CONTEXT-----")     print("\(context)")     print("__________END OF DEBUG INFO_________")      if detailPath == expandedCell {         expandedCell = nil     } else {         expandedCell = detailPath     }      UIView.animate(withDuration: 0.25) {         collectionView.collectionViewLayout.invalidateLayout(with: context)     }     collectionView.layoutIfNeeded() //if this doesn't work then try uncommenting the next line     //collectionView.reloadData()   } 

If all this will not help then paste what you get in those debug print statements. Or you could share the code on github I could try to contribute.

EDIT 1:

// MARK: UICollectionViewDelegate //add @objc to the func below @objc func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {     let width = collectionView.frame.size.width / CGFloat(itemsPerWidth)      if isDetailCell(indexPath: indexPath) {         if expandedCell == indexPath {             return CGSize(width: collectionView.frame.size.width, height: width)         } else {             return CGSize(width: collectionView.frame.size.width, height: 0)         }     } else {         return CGSize(width: width, height: width)     } } 
Read More

How to view code documentation in Visual Studio without opening an external browser instance?

Leave a Comment

If I want to see the full documentation for a class or method in Visual Studio, I have to press F1. This opens an external browser window where I can look it up.

Now, I'd like to see the documentation within the IDE, in an integrated window, without having to mess around with a separate browser window. Additionally I'd like the documentation window to update as soon as I switch the cursor to another method/class/etc. This feature is fairly common in the Java IDEs.

Is there any way to achieve this behavior in Visual Studio?

1 Answers

Answers 1

You can install Help Viewer. See also Video.

If help viewer is already installed follow the instructions here to enable it:

When you install Visual Studio, you get the Help Viewer. To start reading help topics in the Help Viewer rather than on the MSDN download site, go to the Help menu in Visual Studio, select Set Help Preference, and then select Launch in Help Viewer. The off-line help topics for a given version of Visual Studio are available only after the final release of that version.

Beware, downloading help content for offline viewing can take a large amount of disk space!

Read More

Will download resume after closing my app in Background Mode

Leave a Comment

I figured out about it is possible to download in background mode of application. I have implemented Background Fetching Mode in XCode and registered background task and its working fine.

Is it possible to resume downloading task after force closing my application by user? How?

3 Answers

Answers 1

No, you can't continue download when your app get terminated by user! Your app must require to remains in background state!!! Because if user force close app that means, he doesn't want to run it anymore. If your app is suspended by system then it can be wake up but not if it's terminated by user!

If an iOS app is terminated by the system and relaunched, the app can use the same identifier to create a new configuration object and session and retrieve the status of transfers that were in progress at the time of termination. This behavior applies only for normal termination of the app by the system. If the user terminates the app from the multitasking screen, the system cancels all of the session’s background transfers. In addition, the system does not automatically relaunch apps that were force quit by the user. The user must explicitly relaunch the app before transfers can begin again.

Update : (As asked in comment)

Refer the apple documentation, It states,

This method lets your app know that it is about to be terminated and purged from memory entirely. You should use this method to perform any final clean-up tasks for your app, such as freeing shared resources, saving user data, and invalidating timers. Your implementation of this method has approximately five seconds to perform any tasks and return. If the method does not return before time expires, the system may kill the process altogether.

For apps that do not support background execution or are linked against iOS 3.x or earlier, this method is always called when the user quits the app. For apps that support background execution, this method is generally not called when the user quits the app because the app simply moves to the background in that case. However, this method may be called in situations where the app is running in the background (not suspended) and the system needs to terminate it for some reason.

After calling this method, the app also posts a UIApplicationWillTerminate notification to give interested objects a chance to respond to the transition.

Answers 2

When any task completes, the NSURLSession object calls the delegate’s URLSession:task:didCompleteWithError: method with either an error object or nil (if the task completed successfully). If the task failed, most apps should retry the request until either the user cancels the download or the server returns an error indicating that the request will never succeed. Your app should not retry immediately, however. Instead, it should use reachability APIs to determine whether the server is reachable, and should make a new request only when it receives a notification that reachability has changed.

If the download task can be resumed, the NSError object’s userInfo dictionary contains a value for the NSURLSessionDownloadTaskResumeData key. Your app should pass this value to call downloadTaskWithResumeData: or downloadTaskWithResumeData:completionHandler: to create a new download task that continues the existing download.

If the task cannot be resumed, your app should create a new download task and restart the transaction from the beginning.

checkout here: Life cycle of URL Session

Answers 3

Yes—if I understood your need right—Apple allows this with State Preservation and Restoration APIs:

Return your app to its previous state after it is terminated by the system.

Check Apple's article: Preserving Your App's UI Across Launches, for an overview of this framework.

Details about preservation process can be found in article: About the UI Preservation Process

Details about restoration process can be found here: About the UI Restoration Process

Raywenderlich have—a little outdated—tutorial implementation of this framework @ State Restoration Tutorial: Getting Started

Read More

Docker-compose check if mysql connection is ready

Leave a Comment

I am trying to make sure that my app container does not run migrations / start until the db container is started and READY TO accept connections.

So I decided to use the healthcheck and depends on option in docker compose file v2.

In the app, I have the following

app:     ...     depends_on:       db:       condition: service_healthy 

The db on the other hand has the following healthcheck

db:   ...   healthcheck:     test: TEST_GOES_HERE     timeout: 20s     retries: 10 

I have tried a couple of approaches like :

  1. making sure the db DIR is created test: ["CMD", "test -f var/lib/mysql/db"]
  2. Getting the mysql version: test: ["CMD", "echo 'SELECT version();'| mysql"]
  3. Ping the admin (marks the db container as healthy but does not seem to be a valid test) test: ["CMD", "mysqladmin" ,"ping", "-h", "localhost"]

Does anyone have a solution to this?

4 Answers

Answers 1

version: "2.1" services:     api:         build: .         container_name: api         ports:             - "8080:8080"         depends_on:             db:                 condition: service_healthy     db:         container_name: db         image: mysql         ports:             - "3306"         environment:             MYSQL_ALLOW_EMPTY_PASSWORD: "yes"             MYSQL_USER: "user"             MYSQL_PASSWORD: "password"             MYSQL_DATABASE: "database"         healthcheck:             test: ["CMD", "mysqladmin" ,"ping", "-h", "localhost"]             timeout: 20s             retries: 10 

The api container will not start until the db container is healthy (basically until mysqladmin is up and accepting connections.)

Answers 2

If you can change the container to wait for mysql to be ready do it.

If you don't have the control of the container that you want to connect the database to, you can try to wait for the specific port.

For that purpose, I'm using a small script to wait for a specific port exposed by another container.

In this example, myserver will wait for port 3306 of mydb container to be reachable.

# Your database mydb:   image: mysql   ports:     - "3306:3306"   volumes:     - yourDataDir:/var/lib/mysql  # Your server myserver:   image: myserver   ports:     - "....:...."   entrypoint: ./wait-for-it.sh mydb:3306 -- ./yourEntryPoint.sh 

You can find the script wait-for-it documentation here

Answers 3

I modified the docker-compose.yml as per the following example and it worked.

  mysql:     image: mysql:5.6     ports:       - "3306:3306"     volumes:              # Preload files for data       - ../schemaAndSeedData:/docker-entrypoint-initdb.d     environment:       MYSQL_ROOT_PASSWORD: rootPass       MYSQL_DATABASE: DefaultDB       MYSQL_USER: usr       MYSQL_PASSWORD: usr     healthcheck:       test:  mysql --user=root --password=rootPass -e 'Design your own check script ' LastSchema 

In my case ../schemaAndSeedData contains multiple schema and data seeding sql files. Design your own check script can be similar to following select * from LastSchema.LastDBInsert.

While web dependent container code was

depends_on:   mysql:     condition: service_healthy 

Answers 4

Hi for a simple healthcheck, I used:

/usr/bin/mysql --user=root --password=rootpasswd --execute \"SHOW DATABASES;\" 

Basically it runs a simple mysql command SHOW DATABASES; using as an example the user root with the password rootpasswd in the database.

If the command succeed the db is up and ready so the healthcheck path. You can use interval so it tests at interval.

Removing the other field for visibility, here is what it would look like in your docker-compose.yaml.

version: '2.1'    services:     db:       ...       healthcheck:         test: "/usr/bin/mysql --user=root --password=rootpasswd --execute \"SHOW DATABASES;\""         interval: 2s         timeout: 20s         retries: 10       app:        ...        depends_on:          db:          condition: service_healthy 
Read More

How to migrate existing Spring project to Spring Boot

Leave a Comment

I'm trying to migrate existing Spring project to Spring Boot. In project already used Spring Data JPA/Hibernate and simple DAO with JDBC (PostgreSQL used). In few states I found that all that I need to migrate on Spring boot, is:

  1. Add necessary dependencies
  2. Add entry point @SpringBootApplication
  3. profit, that's all.

1) Dependencies:

<dependencyManagement>         <dependencies>             <dependency>                 <groupId>org.springframework.boot</groupId>                 <artifactId>spring-boot-dependencies</artifactId>                 <version>${spring.boot.version}</version>                 <type>pom</type>                 <scope>import</scope>             </dependency>          </dependencies>     </dependencyManagement> <dependency>         <groupId>org.springframework.boot</groupId>         <artifactId>spring-boot-starter-test</artifactId>         <scope>test</scope>     </dependency>     <dependency>         <groupId>com.fasterxml.jackson.core</groupId>         <artifactId>jackson-databind</artifactId>         <version>2.9.4</version>     </dependency> <dependency>             <groupId>org.springframework.data</groupId>             <artifactId>spring-data-jpa</artifactId>             <version>2.0.5.RELEASE</version>         </dependency> <dependency>             <groupId>org.springframework.boot</groupId>             <artifactId>spring-boot-starter-data-jpa</artifactId>             <version>1.4.7.RELEASE</version>         </dependency> <dependency>             <groupId>org.springframework.boot</groupId>             <artifactId>spring-boot-starter-jetty</artifactId>             <version>1.4.7.RELEASE</version>         </dependency> 

With dependencyManagment section I have error:

Exception in thread "main" java.lang.NoSuchMethodError: org.springframework.data.repository.config.RepositoryConfigurationSource.getAttribute(Ljava/lang/String;)Ljava/util/Optional;     at org.springframework.data.jpa.repository.config.JpaRepositoryConfigExtension.postProcess(JpaRepositoryConfigExtension.java:125)     at org.springframework.data.repository.config.RepositoryConfigurationDelegate.registerRepositoriesIn(RepositoryConfigurationDelegate.java:127)     at org.springframework.data.repository.config.RepositoryBeanDefinitionRegistrarSupport.registerBeanDefinitions(RepositoryBeanDefinitionRegistrarSupport.java:83)     at org.springframework.context.annotation.ConfigurationClassBeanDefinitionReader.loadBeanDefinitionsFromRegistrars(ConfigurationClassBeanDefinitionReader.java:359)     at org.springframework.context.annotation.ConfigurationClassBeanDefinitionReader.loadBeanDefinitionsForConfigurationClass(ConfigurationClassBeanDefinitionReader.java:143)     at org.springframework.context.annotation.ConfigurationClassBeanDefinitionReader.loadBeanDefinitions(ConfigurationClassBeanDefinitionReader.java:116)     at org.springframework.context.annotation.ConfigurationClassPostProcessor.processConfigBeanDefinitions(ConfigurationClassPostProcessor.java:320)     at org.springframework.context.annotation.ConfigurationClassPostProcessor.postProcessBeanDefinitionRegistry(ConfigurationClassPostProcessor.java:228)     at org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanDefinitionRegistryPostProcessors(PostProcessorRegistrationDelegate.java:272)     at org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(PostProcessorRegistrationDelegate.java:92)     at org.springframework.context.support.AbstractApplicationContext.invokeBeanFactoryPostProcessors(AbstractApplicationContext.java:687)     at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:525)     at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.refresh(EmbeddedWebApplicationContext.java:122)     at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:693)     at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:360)     at org.springframework.boot.SpringApplication.run(SpringApplication.java:303)     at org.springframework.boot.SpringApplication.run(SpringApplication.java:1118)     at org.springframework.boot.SpringApplication.run(SpringApplication.java:1107)     at ru.testproject.BootConfiguration.main(BootConfiguration.java:26) 

And without it:

Exception in thread "main" org.springframework.context.ApplicationContextException: Unable to start embedded container; nested exception is java.lang.NoClassDefFoundError: org/eclipse/jetty/util/DeprecationWarning     at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.onRefresh(EmbeddedWebApplicationContext.java:137)     at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:543)     at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.refresh(EmbeddedWebApplicationContext.java:122)     at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:693)     at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:360)     at org.springframework.boot.SpringApplication.run(SpringApplication.java:303)     at org.springframework.boot.SpringApplication.run(SpringApplication.java:1118)     at org.springframework.boot.SpringApplication.run(SpringApplication.java:1107)     at ru.testproject.BootConfiguration.main(BootConfiguration.java:26) Caused by: java.lang.NoClassDefFoundError: org/eclipse/jetty/util/DeprecationWarning     at org.eclipse.jetty.servlet.ServletContextHandler.<init>(ServletContextHandler.java:159)     at org.eclipse.jetty.webapp.WebAppContext.<init>(WebAppContext.java:289)     at org.eclipse.jetty.webapp.WebAppContext.<init>(WebAppContext.java:211)     at org.springframework.boot.context.embedded.jetty.JettyEmbeddedWebAppContext.<init>(JettyEmbeddedWebAppContext.java:28)     at org.springframework.boot.context.embedded.jetty.JettyEmbeddedServletContainerFactory.getEmbeddedServletContainer(JettyEmbeddedServletContainerFactory.java:170)     at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.createEmbeddedServletContainer(EmbeddedWebApplicationContext.java:164)     at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.onRefresh(EmbeddedWebApplicationContext.java:134)     ... 8 more Caused by: java.lang.ClassNotFoundException: org.eclipse.jetty.util.DeprecationWarning     at java.net.URLClassLoader.findClass(URLClassLoader.java:381)     at java.lang.ClassLoader.loadClass(ClassLoader.java:424)     at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:349)     at java.lang.ClassLoader.loadClass(ClassLoader.java:357) 

2) entry point (I'm also tried to Import configuration classes, commented):

@SpringBootApplication //@Import({DatabaseConfig.class, WebMvcConfig.class, WebAppConfig.class, WebSecurityConfig.class, WebServiceConfig.class}) public class BootConfiguration extends SpringBootServletInitializer {      public static void main(String[] args) {         SpringApplication.run(BootConfiguration.class, args); //        SpringApplication.run(new Class<?>[] {BootConfiguration.class, DatabaseConfig.class, WebMvcConfig.class, WebAppConfig.class, WebSecurityConfig.class, WebServiceConfig.class}, args);     }      @Bean     public JettyEmbeddedServletContainerFactory jettyEmbeddedServletContainerFactory() {         JettyEmbeddedServletContainerFactory jettyContainer =                 new JettyEmbeddedServletContainerFactory();          jettyContainer.setPort(9000);         jettyContainer.setContextPath("");         return jettyContainer;     }      @Override     protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {         return application.sources(BootConfiguration.class);     } } 

And configuration:

@Configuration @EnableAutoConfiguration(exclude = {DataSourceAutoConfiguration.class, DataSourceTransactionManagerAutoConfiguration.class, HibernateJpaAutoConfiguration.class}) @EnableJpaRepositories(basePackages = {         "ru.testproject.hibernate" }) @EnableTransactionManagement @PropertySource("classpath:application.properties") public class DatabaseConfig implements TransactionManagementConfigurer {      @Bean     public DataSource dataSource() {          if (DB_TYPE_POSTGRESQL.equalsIgnoreCase(dbType)) {             return postresqlDataSource();         } else {             return h2DataSource();         }      }      @Bean     public PlatformTransactionManager annotationDrivenTransactionManager() {         return new JpaTransactionManager();     } } 

I have no idea what I'm doing wrong. What do I need to do to start spring boot application with existing Jetty server configuration?

UPDATE I've modified the main pom:

<parent>         <groupId>ru.testproject</groupId>         <artifactId>test</artifactId>         <version>1.0.1</version>     </parent>  <dependencyManagement>         <dependencies>             <dependency>                 <groupId>org.springframework.boot</groupId>                 <artifactId>spring-boot-dependencies</artifactId>                 <version>${spring.boot.version}</version>                 <type>pom</type>                 <scope>import</scope>             </dependency>          </dependencies>     </dependencyManagement> ... <dependency>             <groupId>org.springframework.boot</groupId>             <artifactId>spring-boot-starter-test</artifactId>             <scope>test</scope>         </dependency>         <dependency>             <groupId>org.springframework.boot</groupId>             <artifactId>spring-boot-starter-data-jpa</artifactId>         </dependency>         <dependency>             <groupId>org.springframework.boot</groupId>             <artifactId>spring-boot-starter-jetty</artifactId>         </dependency> <dependency>             <groupId>org.springframework.boot</groupId>             <artifactId>spring-boot-starter-web-services</artifactId>             <!-- <version>${spring.boot.version}</version> -->             <exclusions>                 <exclusion>                     <groupId>org.springframework.boot</groupId>                     <artifactId>spring-boot-starter-tomcat</artifactId>                 </exclusion>                  <exclusion>                     <groupId>org.springframework.boot</groupId>                     <artifactId>spring-boot-starter-logging</artifactId>                 </exclusion>                 <exclusion>                     <groupId>org.springframework.boot</groupId>                     <artifactId>spring-boot-starter-validation</artifactId>                 </exclusion>                 <exclusion>                     <groupId>org.jboss.logging</groupId>                     <artifactId>jboss-logging</artifactId>                 </exclusion>                 <exclusion>                     <groupId>com.fasterxml.jackson.core</groupId>                     <artifactId>jackson-core</artifactId>                 </exclusion>                 <exclusion>                     <groupId>com.fasterxml.jackson.core</groupId>                     <artifactId>jackson-databind</artifactId>                 </exclusion>                 <exclusion>                     <groupId>com.fasterxml.jackson.core</groupId>                     <artifactId>jackson-annotations</artifactId>                 </exclusion>                 <exclusion>                     <groupId>org.hibernate</groupId>                     <artifactId>hibernate-validator</artifactId>                 </exclusion>              </exclusions>         </dependency>  <!-- Hibernate -->         <dependency>             <groupId>org.hibernate</groupId>             <artifactId>hibernate-entitymanager</artifactId>             <version>${hibernate-version}</version>         </dependency>         <dependency>             <groupId>org.hibernate</groupId>             <artifactId>hibernate-core</artifactId>             <version>${hibernate-version}</version>         </dependency>         <dependency>             <groupId>org.hibernate.javax.persistence</groupId>             <artifactId>hibernate-jpa-2.0-api</artifactId>             <version>1.0.1.Final</version>         </dependency>  <dependency>             <groupId>org.springframework</groupId>             <artifactId>spring-webmvc</artifactId>             <version>${spring.version}</version>         </dependency>          <dependency>             <groupId>org.springframework.security</groupId>             <artifactId>spring-security-config</artifactId>             <version>4.2.1.RELEASE</version>         </dependency>          <dependency>             <groupId>org.springframework.security</groupId>             <artifactId>spring-security-web</artifactId>             <version>4.2.0.RELEASE</version>         </dependency>          <dependency>             <groupId>org.springframework.security</groupId>             <artifactId>spring-security-taglibs</artifactId>             <version>4.2.0.RELEASE</version>         </dependency>          <dependency>             <groupId>org.springframework</groupId>             <artifactId>spring-jdbc</artifactId>             <version>${spring.version}</version>         </dependency> <!-- Version 5.0.4 because ${spring.version} context fails with CandidateComponentsIndexLoader error (it introduced in 5.0.0 version) -->         <dependency>             <groupId>org.springframework</groupId>             <artifactId>spring-context</artifactId>             <version>5.0.4.RELEASE</version>         </dependency>         <dependency>             <groupId>org.springframework</groupId>             <artifactId>spring-context-support</artifactId>             <version>${spring.version}</version>         </dependency>         <dependency>             <groupId>org.springframework</groupId>             <artifactId>spring-tx</artifactId>             <version>${spring.version}</version>         </dependency>         <dependency>             <groupId>javax.xml.bind</groupId>             <artifactId>jaxb-api</artifactId>             <version>2.3.0</version>         </dependency>          <!-- Jetty embedded -->         <dependency>             <groupId>javax.servlet</groupId>             <artifactId>javax.servlet-api</artifactId>             <version>3.1.0</version>         </dependency> 

also, I've commented all tags for spring boot dependencies. mvc dependency:tree give the following output:

[INFO] --- maven-dependency-plugin:3.0.2:tree (default-cli) @ test --- [WARNING] The artifact org.hibernate:hibernate-infinispan:jar:5.3.3.Final has been relocated to org.infinispan:infinispan-hibernate-cache-v53:jar:9.3.0.Final [INFO] ru.testproject:test:jar:2.4.41-SNAPSHOT [INFO] +- org.springframework.boot:spring-boot-starter-test:jar:1.5.8.RELEASE:test [INFO] |  +- org.springframework.boot:spring-boot-test:jar:1.5.8.RELEASE:test [INFO] |  |  \- org.springframework.boot:spring-boot:jar:1.5.8.RELEASE:compile [INFO] |  +- org.springframework.boot:spring-boot-test-autoconfigure:jar:1.5.8.RELEASE:test [INFO] |  |  \- org.springframework.boot:spring-boot-autoconfigure:jar:1.5.8.RELEASE:compile [INFO] |  +- com.jayway.jsonpath:json-path:jar:2.2.0:test [INFO] |  |  \- net.minidev:json-smart:jar:2.2.1:test [INFO] |  |     \- net.minidev:accessors-smart:jar:1.1:test [INFO] |  +- org.assertj:assertj-core:jar:2.6.0:test [INFO] |  +- org.mockito:mockito-core:jar:1.10.19:test [INFO] |  |  \- org.objenesis:objenesis:jar:2.1:test [INFO] |  +- org.hamcrest:hamcrest-core:jar:1.3:test [INFO] |  +- org.hamcrest:hamcrest-library:jar:1.3:test [INFO] |  +- org.skyscreamer:jsonassert:jar:1.4.0:test [INFO] |  |  \- com.vaadin.external.google:android-json:jar:0.0.20131108.vaadin1:test [INFO] |  +- org.springframework:spring-core:jar:4.3.12.RELEASE:compile [INFO] |  \- org.springframework:spring-test:jar:4.3.12.RELEASE:test [INFO] +- org.springframework.boot:spring-boot-starter-data-jpa:jar:1.5.8.RELEASE:compile [INFO] |  +- org.springframework.boot:spring-boot-starter:jar:1.5.8.RELEASE:compile [INFO] |  |  +- org.springframework.boot:spring-boot-starter-logging:jar:1.5.8.RELEASE:compile [INFO] |  |  |  +- ch.qos.logback:logback-classic:jar:1.1.11:compile [INFO] |  |  |  |  \- ch.qos.logback:logback-core:jar:1.1.11:compile [INFO] |  |  |  +- org.slf4j:jul-to-slf4j:jar:1.7.25:compile [INFO] |  |  |  \- org.slf4j:log4j-over-slf4j:jar:1.7.25:compile [INFO] |  |  \- org.yaml:snakeyaml:jar:1.17:runtime [INFO] |  +- org.springframework.boot:spring-boot-starter-aop:jar:1.5.8.RELEASE:compile [INFO] |  |  \- org.aspectj:aspectjweaver:jar:1.8.11:compile [INFO] |  +- org.springframework.boot:spring-boot-starter-jdbc:jar:1.5.8.RELEASE:compile [INFO] |  |  \- org.apache.tomcat:tomcat-jdbc:jar:8.5.23:compile [INFO] |  |     \- org.apache.tomcat:tomcat-juli:jar:8.5.23:compile [INFO] |  +- javax.transaction:javax.transaction-api:jar:1.2:compile [INFO] |  +- org.springframework.data:spring-data-jpa:jar:1.11.8.RELEASE:compile [INFO] |  |  +- org.springframework.data:spring-data-commons:jar:1.13.8.RELEASE:compile [INFO] |  |  +- org.springframework:spring-orm:jar:4.3.12.RELEASE:compile [INFO] |  |  \- org.slf4j:jcl-over-slf4j:jar:1.7.25:compile [INFO] |  \- org.springframework:spring-aspects:jar:4.3.12.RELEASE:compile [INFO] +- org.springframework.boot:spring-boot-starter-jetty:jar:1.5.8.RELEASE:compile [INFO] |  +- org.eclipse.jetty:jetty-webapp:jar:9.4.7.v20170914:compile [INFO] |  |  +- org.eclipse.jetty:jetty-xml:jar:9.4.7.v20170914:compile [INFO] |  |  \- org.eclipse.jetty:jetty-servlet:jar:9.4.7.v20170914:compile [INFO] |  |     \- org.eclipse.jetty:jetty-security:jar:9.4.7.v20170914:compile [INFO] |  |        \- org.eclipse.jetty:jetty-server:jar:9.4.7.v20170914:compile [INFO] |  +- org.eclipse.jetty.websocket:websocket-server:jar:9.4.7.v20170914:compile [INFO] |  |  +- org.eclipse.jetty.websocket:websocket-common:jar:9.4.7.v20170914:compile [INFO] |  |  |  \- org.eclipse.jetty.websocket:websocket-api:jar:9.4.7.v20170914:compile [INFO] |  |  +- org.eclipse.jetty.websocket:websocket-client:jar:9.4.7.v20170914:compile [INFO] |  |  |  \- org.eclipse.jetty:jetty-client:jar:9.4.7.v20170914:compile [INFO] |  |  \- org.eclipse.jetty.websocket:websocket-servlet:jar:9.4.7.v20170914:compile [INFO] |  +- org.eclipse.jetty.websocket:javax-websocket-server-impl:jar:9.4.7.v20170914:compile [INFO] |  |  +- org.eclipse.jetty:jetty-annotations:jar:9.4.7.v20170914:compile [INFO] |  |  |  +- org.eclipse.jetty:jetty-plus:jar:9.4.7.v20170914:compile [INFO] |  |  |  +- javax.annotation:javax.annotation-api:jar:1.2:compile [INFO] |  |  |  +- org.ow2.asm:asm:jar:5.1:compile [INFO] |  |  |  \- org.ow2.asm:asm-commons:jar:5.1:compile [INFO] |  |  |     \- org.ow2.asm:asm-tree:jar:5.1:compile [INFO] |  |  +- org.eclipse.jetty.websocket:javax-websocket-client-impl:jar:9.4.7.v20170914:compile [INFO] |  |  \- javax.websocket:javax.websocket-api:jar:1.0:compile [INFO] |  \- org.mortbay.jasper:apache-el:jar:8.0.33:compile [INFO] +- commons-fileupload:commons-fileupload:jar:1.3.1:compile [INFO] +- org.springframework.boot:spring-boot-starter-web-services:jar:1.5.8.RELEASE:compile [INFO] |  +- org.springframework.boot:spring-boot-starter-web:jar:1.5.8.RELEASE:compile [INFO] |  +- org.springframework:spring-oxm:jar:4.3.12.RELEASE:compile [INFO] |  \- org.springframework.ws:spring-ws-core:jar:2.4.0.RELEASE:compile [INFO] |     \- org.springframework.ws:spring-xml:jar:2.4.0.RELEASE:compile [INFO] +- org.hibernate:hibernate-entitymanager:jar:5.3.3.Final:compile [INFO] |  +- org.jboss.logging:jboss-logging:jar:3.3.1.Final:compile [INFO] |  +- dom4j:dom4j:jar:1.6.1:compile [INFO] |  +- org.hibernate.common:hibernate-commons-annotations:jar:5.0.4.Final:compile [INFO] |  +- javax.persistence:javax.persistence-api:jar:2.2:compile [INFO] |  +- net.bytebuddy:byte-buddy:jar:1.8.13:compile [INFO] |  \- org.jboss.spec.javax.transaction:jboss-transaction-api_1.2_spec:jar:1.1.1.Final:compile [INFO] +- org.hibernate:hibernate-core:jar:5.3.3.Final:compile [INFO] |  +- org.javassist:javassist:jar:3.21.0-GA:compile [INFO] |  +- antlr:antlr:jar:2.7.7:compile [INFO] |  +- org.jboss:jandex:jar:2.0.5.Final:compile [INFO] |  +- com.fasterxml:classmate:jar:1.3.4:compile [INFO] |  \- javax.activation:javax.activation-api:jar:1.2.0:compile [INFO] +- org.hibernate.javax.persistence:hibernate-jpa-2.0-api:jar:1.0.1.Final:compile [INFO] +- org.hibernate:hibernate-osgi:jar:5.3.3.Final:compile [INFO] |  +- javax.interceptor:javax.interceptor-api:jar:1.2:compile [INFO] |  +- org.osgi:org.osgi.core:jar:6.0.0:compile [INFO] |  \- org.osgi:org.osgi.compendium:jar:5.0.0:compile [INFO] +- org.hibernate:hibernate-envers:jar:5.3.3.Final:compile [INFO] +- org.hibernate:hibernate-hikaricp:jar:5.3.3.Final:compile [INFO] +- org.hibernate:hibernate-proxool:jar:5.3.3.Final:compile [INFO] |  \- proxool:proxool:jar:0.8.3:compile [INFO] +- org.infinispan:infinispan-hibernate-cache-v53:jar:9.3.0.Final:compile [INFO] |  +- org.infinispan:infinispan-hibernate-cache-commons:jar:9.3.0.Final:compile [INFO] |  +- org.infinispan:infinispan-hibernate-cache-spi:jar:9.3.0.Final:compile [INFO] |  \- org.infinispan:infinispan-core:jar:9.3.0.Final:compile [INFO] |     +- org.infinispan:infinispan-commons:jar:9.3.0.Final:compile [INFO] |     +- org.jgroups:jgroups:jar:4.0.12.Final:compile [INFO] |     +- com.github.ben-manes.caffeine:caffeine:jar:2.3.5:compile [INFO] |     +- org.jboss.spec.javax.transaction:jboss-transaction-api_1.1_spec:jar:1.0.1.Final:compile [INFO] |     +- org.jboss.marshalling:jboss-marshalling-osgi:jar:2.0.5.Final:compile [INFO] |     \- io.reactivex.rxjava2:rxjava:jar:2.1.3:compile [INFO] |        \- org.reactivestreams:reactive-streams:jar:1.0.1:compile [INFO] +- org.hibernate:hibernate-ehcache:jar:5.3.3.Final:compile [INFO] |  \- net.sf.ehcache:ehcache:jar:2.10.4:compile [INFO] +- wsdl4j:wsdl4j:jar:1.6.1:compile [INFO] +- org.springframework:spring-webmvc:jar:4.3.12.RELEASE:compile [INFO] |  +- org.springframework:spring-aop:jar:4.3.12.RELEASE:compile [INFO] |  +- org.springframework:spring-beans:jar:4.3.12.RELEASE:compile [INFO] |  +- org.springframework:spring-expression:jar:4.3.12.RELEASE:compile [INFO] |  \- org.springframework:spring-web:jar:4.3.12.RELEASE:compile [INFO] +- org.springframework.security:spring-security-config:jar:4.2.1.RELEASE:compile [INFO] |  +- aopalliance:aopalliance:jar:1.0:compile [INFO] |  \- org.springframework.security:spring-security-core:jar:4.2.3.RELEASE:compile [INFO] +- org.springframework.security:spring-security-web:jar:4.2.0.RELEASE:compile [INFO] +- org.springframework.security:spring-security-taglibs:jar:4.2.0.RELEASE:compile [INFO] |  \- org.springframework.security:spring-security-acl:jar:4.2.3.RELEASE:compile [INFO] +- org.springframework:spring-jdbc:jar:4.3.12.RELEASE:compile [INFO] +- org.springframework:spring-context:jar:5.0.4.RELEASE:compile [INFO] +- org.springframework:spring-context-support:jar:4.3.12.RELEASE:compile [INFO] +- org.springframework:spring-tx:jar:4.3.12.RELEASE:compile [INFO] +- javax.xml.bind:jaxb-api:jar:2.3.0:compile [INFO] +- javax.servlet:javax.servlet-api:jar:3.1.0:compile [INFO] +- javax.inject:javax.inject:jar:1:compile [INFO] +- commons-configuration:commons-configuration:jar:1.10:compile [INFO] |  \- commons-logging:commons-logging:jar:1.1.1:compile [INFO] +- commons-lang:commons-lang:jar:2.6:compile [INFO] +- junit:junit:jar:4.11:test [INFO] +- org.jdom:jdom:jar:2.0.2:compile [INFO] +- commons-io:commons-io:jar:2.4:compile [INFO] +- xalan:xalan:jar:2.7.2:compile [INFO] |  \- xalan:serializer:jar:2.7.2:compile [INFO] |     \- xml-apis:xml-apis:jar:1.4.01:compile [INFO] +- org.apache.derby:derby:jar:10.11.1.1:compile [INFO] +- org.postgresql:postgresql:jar:42.1.1:compile [INFO] +- com.zaxxer:HikariCP:jar:2.6.3:compile [INFO] |  \- org.slf4j:slf4j-api:jar:1.7.25:compile [INFO] +- jaxen:jaxen:jar:1.1.6:compile [INFO] +- ru.testproject:test-conf:jar:2.4.41-SNAPSHOT:compile [INFO] |  +- log4j:log4j:jar:1.2.16:compile [INFO] |  +- org.slf4j:slf4j-log4j12:jar:1.7.25:compile [INFO] |  \- ru.testproject:test-util:jar:2.4.41-SNAPSHOT:compile [INFO] +- com.github.spullara.mustache.java:compiler:jar:0.9.0:compile [INFO] +- org.quartz-scheduler:quartz:jar:2.2.1:compile [INFO] |  \- c3p0:c3p0:jar:0.9.1.1:compile [INFO] +- javax.json:javax.json-api:jar:1.0:compile [INFO] +- org.apache.santuario:xmlsec:jar:2.0.6:compile [INFO] |  +- org.codehaus.woodstox:woodstox-core-asl:jar:4.4.1:compile [INFO] |  |  +- javax.xml.stream:stax-api:jar:1.0-2:compile [INFO] |  |  \- org.codehaus.woodstox:stax2-api:jar:3.1.4:compile [INFO] |  \- commons-codec:commons-codec:jar:1.10:compile [INFO] +- org.eclipse.jetty:jetty-servlets:jar:9.3.5.v20151012:compile [INFO] |  +- org.eclipse.jetty:jetty-continuation:jar:9.4.7.v20170914:compile [INFO] |  +- org.eclipse.jetty:jetty-http:jar:9.4.7.v20170914:compile [INFO] |  +- org.eclipse.jetty:jetty-util:jar:9.4.7.v20170914:compile [INFO] |  \- org.eclipse.jetty:jetty-io:jar:9.4.7.v20170914:compile [INFO] +- com.itextpdf:itextpdf:jar:5.5.12:compile [INFO] +- org.bouncycastle:bcprov-jdk15on:jar:1.55:compile [INFO] +- org.bouncycastle:bcmail-jdk15on:jar:1.55:compile [INFO] +- org.bouncycastle:bcpkix-jdk15on:jar:1.55:compile [INFO] +- com.google.guava:guava:jar:24.0-jre:compile [INFO] |  +- com.google.code.findbugs:jsr305:jar:1.3.9:compile [INFO] |  +- org.checkerframework:checker-compat-qual:jar:2.0.0:compile [INFO] |  +- com.google.errorprone:error_prone_annotations:jar:2.1.3:compile [INFO] |  +- com.google.j2objc:j2objc-annotations:jar:1.1:compile [INFO] |  \- org.codehaus.mojo:animal-sniffer-annotations:jar:1.14:compile [INFO] +- org.dom4j:dom4j:jar:2.1.0:compile [INFO] +- com.fasterxml.jackson.core:jackson-databind:jar:2.8.10:compile [INFO] |  +- com.fasterxml.jackson.core:jackson-annotations:jar:2.8.0:compile [INFO] |  \- com.fasterxml.jackson.core:jackson-core:jar:2.8.10:compile [INFO] +- commons-net:commons-net:jar:3.6:compile [INFO] +- org.samba.jcifs:jcifs:jar:1.2.19:compile [INFO] \- org.reflections:reflections:jar:0.9.11:compile [INFO] ------------------------------------------------------------------------ [INFO] BUILD SUCCESS [INFO] ------------------------------------------------------------------------ [INFO] Total time: 15.788 s [INFO] Finished at: 2018-08-22T11:11:41+03:00 [INFO] ------------------------------------------------------------------------ 

Anyway, I have the same issue at application startup:

    Warning: SLF4J: Class path contains multiple SLF4J bindings.     33:08.275 [main] DEBUG org.springframework.boot.logging.ClasspathLoggingApplicationListener - Application failed to start with classpath:  [main] ERROR org.springframework.boot.SpringApplication - Application startup failed java.lang.NoSuchMethodError: org.springframework.util.ObjectUtils.unwrapOptional(Ljava/lang/Object;)Ljava/lang/Object;         at org.springframework.validation.DataBinder.<init>(DataBinder.java:179)         at org.springframework.boot.bind.RelaxedDataBinder.<init>(RelaxedDataBinder.java:83)         org.springframework.boot.context.config.ConfigFileApplicationListener.postProcessEnvironment(ConfigFileApplicationListener.java:197)         org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:127)         at org.springframework.boot.context.event.EventPublishingRunListener.environmentPrepared(EventPublishingRunListener.java:74)         at org.springframework.boot.SpringApplicationRunListeners.environmentPrepared(SpringApplicationRunListeners.java:54)         at org.springframework.boot.SpringApplication.prepareEnvironment(SpringApplication.java:325)     org.springframework.boot.SpringApplication.run(SpringApplication.java:1107)         at ru.testproject.BootConfiguration.main(BootConfiguration.java:26)     cess finished with exit code 1 

1 Answers

Answers 1

Problem solved: I fixed the dependency issues. Should use,

@Configuration @EnableAutoConfiguration @ComponentScan @Import(Config.class) 

instead @SpringBootApplication annotation.
Now the application is getting booted, but cannot find config file which is another story.

Read More

Thursday, August 30, 2018

Taking the state of one activity to another

Leave a Comment

I have two activity screens: Create and View. Create is where the user creates their shopping list. View is where they view their list (and can still add items).

I've tried reading about saving the instance state of activities but I'm still confused as to **how I can make it so when the user chooses items from the dropdowns in the create screen, those are copied, into the view screen. So basically both screens look the same - i.e the dropdowns with the selected items are in the view screen as well. (So like, the exact view instance from the create screen is copied into the view screen)

Below is my create.java code. (view.java has exactly the same code just with .view in places instead of .create, and some extra code.)

public class create extends AppCompatActivity {       private LinearLayout mLinearLayout;     private ArrayList<SearchableSpinner> mSpinners;     //TODO add the below list of buttons and checkboxes    // private List<AppCompatButton> mButtons = new ArrayList<>();     private List<CheckBox> mCheckboxes = new ArrayList<>();     private List<View> mViews = new ArrayList<>();     Button buttonGo;     Spinner spinner;       //Button buttontest;       @Override     protected void onCreate(Bundle savedInstanceState) {         super.onCreate(savedInstanceState);         setContentView(R.layout.activity_create);         getSupportActionBar().setDisplayHomeAsUpEnabled(true);          GlobalClass globalClass = (GlobalClass) this.getApplicationContext();           ArrayList<String> items = new ArrayList<>();         items.add(String.valueOf(mSpinners)); // add you selected item         globalClass.setItems(items);           mSpinners = new ArrayList<>();          mLinearLayout = findViewById(R.id.my_linearLayout);                 FloatingActionButton floatingActionButton =                 (FloatingActionButton) findViewById(R.id.fab);          floatingActionButton.setOnClickListener(new View.OnClickListener() {             @Override             public void onClick(View view) {                 Toast.makeText(getBaseContext(), "Item added!", Toast.LENGTH_SHORT).show();                  RelativeLayout.LayoutParams params1 = new RelativeLayout.LayoutParams(WindowManager.LayoutParams.WRAP_CONTENT, WindowManager.LayoutParams.WRAP_CONTENT);                 RelativeLayout.LayoutParams params2 = new RelativeLayout.LayoutParams(WindowManager.LayoutParams.WRAP_CONTENT, WindowManager.LayoutParams.WRAP_CONTENT);                 // Handle the click.                   // Handle ze click.                 //final Spinner spinner = makeSpinner();                 //mLinearLayout.addView(spinner);                  //final Spinner                 spinner = makeSpinner();                 spinner.setId(1);                 mLinearLayout.addView(spinner,params1);                        LinearLayout.LayoutParams layoutParams = (LinearLayout.LayoutParams) spinner.getLayoutParams();                 layoutParams.setMargins(5, 100, 10, 0); //top 70                  Resources resources = getResources();                 DisplayMetrics metrics = resources.getDisplayMetrics();                  layoutParams.height = (int) (70 * ((float) metrics.densityDpi / DisplayMetrics.DENSITY_DEFAULT)); //80                 layoutParams.width = (int) (240 * ((float) metrics.densityDpi / DisplayMetrics.DENSITY_DEFAULT)); //240                 spinner.setLayoutParams(layoutParams);                    //TODO adds a new view that is suppose to replicate the button so when it is pressed, blah happens.                 //TODO i.e move the button code to the onclick View then delete button cause its useless.                 //Add a new view                 final View newView = makeView();                 mLinearLayout.addView(newView);                  //TODO create new layout params here                   mViews.add(newView);                   //Add a new button              //   final AppCompatButton newButton = makeButton();                // mLinearLayout.addView(newButton);      // Add another button               //  //TODO add button to the list              //   mButtons.add(newButton);                  final int listSize = mViews.size();                   //code for deleting the said item.                 newView.setOnClickListener(new View.OnClickListener() { //start                      @Override                     public void onClick(View view) {                          //when the 'new button' is pressed, alert shows if you are sure you want to delete the item or not.                          final View.OnClickListener context = this;                           AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(create.this);                           // set title                         alertDialogBuilder.setTitle("Delete Item");                          // set dialog message                         alertDialogBuilder                                 .setMessage("Are you sure you want to delete this item?")                                 .setCancelable(false)                                 .setPositiveButton("Yes", new DialogInterface.OnClickListener() {                                     public void onClick(DialogInterface dialog, int id) {                                         // if this button is clicked, close                                         // current activity                                           if (listSize > 0) {                                            //  mButtons.get(listSize - 1).setVisibility(View.GONE);                                             mCheckboxes.get(listSize - 1).setVisibility(View.GONE);                                             mSpinners.get(listSize - 1).setVisibility(View.GONE);                                             mViews.get(listSize - 1).setVisibility(View.GONE);                                             Toast.makeText(getBaseContext(), "Item removed.", Toast.LENGTH_SHORT).show();                                          }                                       }                                 })                                 .setNegativeButton("No", new DialogInterface.OnClickListener() {                                     public void onClick(DialogInterface dialog, int id) {                                         // if this button is clicked, just close                                         // the dialog box and do nothing                                         dialog.cancel();                                     }                                 });                          // create alert dialog                         AlertDialog alertDialog = alertDialogBuilder.create();                          // show it                         alertDialog.show();                       }                 });                     //Add a new checkbox                 //final CheckBox newCheckbox = makeCheckbox();                 //mLinearLayout.addView(newCheckbox);                  //TODO add checkbox to your list                  final CheckBox newCheckbox = makeCheckbox();                 newCheckbox.setId(2);                 params2.addRule(RelativeLayout.RIGHT_OF, spinner.getId());                 mLinearLayout.addView(newCheckbox,params2);                 mCheckboxes.add(newCheckbox);                       }         });             buttonGo.setOnClickListener(new View.OnClickListener() {                                         public void onClick(View v) {                                              if(spinner!=null){                                                  Intent i= new Intent(create.this, viewscreen.class);                                                 //Create the bundle                                                 Bundle bundle = new Bundle();                                                  //Add your data to bundle                                                 bundle.putString("dropdown", String.valueOf(spinner.getOnItemSelectedListener()));                                                  //Add the bundle to the intent                                                 i.putExtras(bundle);                                                 startActivity(i);                                             }                                         };       });     }       //DUPLICATING ITEMS WHEN FAB IS PRESSED//      private CheckBox makeCheckbox() {         //Create new Checkbox         CheckBox checkbox = new CheckBox(this);          // Setup layout         LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(                 LinearLayout.LayoutParams.MATCH_PARENT,                 LinearLayout.LayoutParams.WRAP_CONTENT);         checkbox.setLayoutParams(layoutParams);          return checkbox;     }       private View makeView() {         //create new View          View view = new View(this);         view.setBackgroundColor(Color.parseColor("#ffffff"));         LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, 100);         new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, 50);         //LinearLayout.LayoutParams.MATCH_PARENT,         // LinearLayout.LayoutParams.WRAP_CONTENT);         view.setClickable(true); //setting if clickable - made it work.             view.setLayoutParams(layoutParams);           //setup layout          return view;       }        private Spinner makeSpinner() {         //opens csv         InputStream inputStream = getResources().openRawResource(R.raw.shopitems);         CSVFile csvFile = new CSVFile(inputStream);         List<String> itemList = csvFile.read();          //Create new spinner         // SearchableSpinner spinner = (SearchableSpinner) new Spinner(this, Spinner.MODE_DROPDOWN);         SearchableSpinner spinner = new SearchableSpinner(this);           // Setup layout         LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(                 LinearLayout.LayoutParams.MATCH_PARENT,                 LinearLayout.LayoutParams.WRAP_CONTENT);         spinner.setLayoutParams(layoutParams);         MyListAdapter adapter = new MyListAdapter(this, R.layout.listrow, R.id.txtid, itemList);           spinner.setAdapter(adapter);           //Add it to your list of spinners so you can retrieve their data when you click the getSpinner button         mSpinners.add(spinner);         return spinner;         }              private class CSVFile {          InputStream inputStream;           public CSVFile(InputStream inputStream) {              this.inputStream = inputStream;          }           public List<String> read() {               List<String> resultList = new ArrayList<String>();              BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));              try {                  String line;                  while ((line = reader.readLine()) != null) {                      String[] row = line.split(",");                      resultList.add(row[1]);                  }              } catch (IOException e) {                  Log.e("Main", e.getMessage());              } finally {                  try {                      inputStream.close();                  } catch (IOException e) {                      Log.e("Main", e.getMessage());                  }              }              return resultList;          }      } }     

UPDATED CODE from Angus' help:

//Create the bundle                 Intent i= new Intent(this, view.class);                   Bundle bundle = new Bundle();                  //Add your data to bundle                 bundle.putString("dropdown", spinner.getOnItemSelectedListener();                  //Add the bundle to the intent                 i.putExtras(bundle);                 startActivity(i); 

Error log:

In the error log it just says a ) expected on the line bundle.putString("dropdown", spinner.getOnItemSelectedListener();

But in the actual code when I hover on the red underline of this line: Intent i= new Intent(this, view.class); it says:Cannot resolve constructor

Second activity code (view)

public class viewscreen extends AppCompatActivity {       private LinearLayout mLinearLayout;     private ArrayList<SearchableSpinner> mSpinners;     //TODO add the below list of buttons and checkboxes     private List<AppCompatButton> mButtons = new ArrayList<>();     private List<CheckBox> mCheckboxes = new ArrayList<>();     //Button buttontest;          @Override     protected void onCreate(Bundle savedInstanceState) {         super.onCreate(savedInstanceState);         setContentView(R.layout.activity_view);         getSupportActionBar().setDisplayHomeAsUpEnabled(true);           mSpinners = new ArrayList<>();          mLinearLayout = findViewById(R.id.my_linearLayout);           GlobalClass globalClass = (GlobalClass) this.getApplicationContext();         ArrayList<String> items = globalClass.getItems();           //mLinearLayout.addView(makeSpinner());    // First spinner               //code for the add button to add more items         FloatingActionButton floatingActionButton =                 (FloatingActionButton) findViewById(R.id.fab);          floatingActionButton.setOnClickListener(new View.OnClickListener() {             @Override             public void onClick(View view) {                 Toast.makeText(getBaseContext(), "Item added!" , Toast.LENGTH_SHORT ).show();                    // Handle ze click.                 final Spinner spinner = makeSpinner();                 mLinearLayout.addView(spinner); //Add another spinner                   LinearLayout.LayoutParams layoutParams = (LinearLayout.LayoutParams)spinner.getLayoutParams();                 layoutParams.setMargins( 5,  100,  10,  0); //top 70                  Resources resources = getResources();                 DisplayMetrics metrics = resources.getDisplayMetrics();                  layoutParams.height = (int) (70 * ((float)metrics.densityDpi / DisplayMetrics.DENSITY_DEFAULT)); //80                 layoutParams.width = (int) (240 * ((float)metrics.densityDpi / DisplayMetrics.DENSITY_DEFAULT)); //240                 spinner.setLayoutParams(layoutParams);                     //Add a new button                 final AppCompatButton newButton = makeButton();                 mLinearLayout.addView(newButton);      // Add another button                 //TODO add button to the list                 mButtons.add(newButton);                 final int listSize = mButtons.size();                        //code for deleting the said item.                 newButton.setOnClickListener(new View.OnClickListener() { //start                      @Override                     public void onClick(View view) {                          //when the 'new button' is pressed, alert shows if you are sure you want to delete the item or not.                          final View.OnClickListener context = this;                           AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(viewscreen.this);                           // set title                         alertDialogBuilder.setTitle("Delete Item");                          // set dialog message                         alertDialogBuilder                                 .setMessage("Are you sure you want to delete this item?")                                 .setCancelable(false)                                 .setPositiveButton("Yes",new DialogInterface.OnClickListener() {                                     public void onClick(DialogInterface dialog,int id) {                                         // if this button is clicked, close                                         // current activity // when list size =  0. show message  all done                                          if(listSize >0) {                                              mButtons.get(listSize - 1).setVisibility(View.GONE);                                             mCheckboxes.get(listSize - 1).setVisibility(View.GONE);                                             mSpinners.get(listSize - 1).setVisibility(View.GONE);                                             Toast.makeText(getBaseContext(), "Item removed." , Toast.LENGTH_SHORT ).show();                                          }                                       }                                 })                                 .setNegativeButton("No",new DialogInterface.OnClickListener() {                                     public void onClick(DialogInterface dialog,int id) {                                         // if this button is clicked, just close                                         // the dialog box and do nothing                                         dialog.cancel();                                     }                                 });                          // create alert dialog                         AlertDialog alertDialog = alertDialogBuilder.create();                          // show it                         alertDialog.show();                        } } );                      //Add a new checkbox                 final CheckBox newCheckbox = makeCheckbox();                 mLinearLayout.addView(newCheckbox);                  //TODO add checkbox to your list                 mCheckboxes.add(newCheckbox);                   //code for checkbox on click is suppose to be in view screen.                     newCheckbox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {                     public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {                         // makes the set disappear when checkbox is ticked.                          newCheckbox.setVisibility(View.VISIBLE);                         newButton.setVisibility(View.VISIBLE);                         spinner.setVisibility(View.VISIBLE);                          newCheckbox.animate().alpha(0.0f).setDuration(1000).setListener(new AnimatorListenerAdapter() {                             @Override                             public void onAnimationEnd(Animator animation) {                                 super.onAnimationEnd(animation);                                 newCheckbox.setVisibility(View.GONE);                             }                         });                          newButton.animate().alpha(0.0f).setDuration(1000).setListener(new AnimatorListenerAdapter() {                             @Override                             public void onAnimationEnd(Animator animation) {                                 super.onAnimationEnd(animation);                                 newButton.setVisibility(View.GONE);                             }                         });                          spinner.animate().alpha(0.0f).setDuration(1000).setListener(new AnimatorListenerAdapter() {                             @Override                             public void onAnimationEnd(Animator animation) {                                 super.onAnimationEnd(animation);                                 spinner.setVisibility(View.GONE);                             }                         });                      }                 });   //end of checkbox on click code.                   Bundle bundle = getIntent().getExtras();                  //Extract the data…                 String dropdown_value= bundle.getString("dropdown");                   }         });            }   //DUPLICATING ITEMS WHEN + IS PRESSED      private CheckBox makeCheckbox() {         //Create new Checkbox         CheckBox checkbox = new CheckBox(this);          // Setup layout         LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(                 LinearLayout.LayoutParams.MATCH_PARENT,                 LinearLayout.LayoutParams.WRAP_CONTENT);         checkbox.setLayoutParams(layoutParams);         return checkbox;     }            private AppCompatButton makeButton() { //creates new buttons I need         //Create new Button         AppCompatButton button = new AppCompatButton(this);         // code for deleting the buttons i need //         //buttontest.setOnClickListener(new View.OnClickListener() {         //   @Override         //   public void onClick(View v) {                // Setup layout         LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(                 LinearLayout.LayoutParams.MATCH_PARENT,                 LinearLayout.LayoutParams.WRAP_CONTENT);         button.setBackgroundColor(Color.parseColor("#ffffff"));           return button;     }      private Spinner makeSpinner() {         //opens csv         InputStream inputStream = getResources().openRawResource(R.raw.shopitems);         CSVFile csvFile = new CSVFile(inputStream);         List<String> itemList = csvFile.read();          //Create new spinner         // SearchableSpinner spinner = (SearchableSpinner) new Spinner(this, Spinner.MODE_DROPDOWN);         SearchableSpinner spinner = new SearchableSpinner(this);             // Setup layout         LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(                 LinearLayout.LayoutParams.MATCH_PARENT,                 LinearLayout.LayoutParams.WRAP_CONTENT);         spinner.setLayoutParams(layoutParams);         MyListAdapter adapter = new MyListAdapter(this, R.layout.listrow, R.id.txtid, itemList);           spinner.setAdapter(adapter);             //Add it to your list of spinners so you can retrieve their data when you click the getSpinner button         mSpinners.add(spinner);         return spinner;     }        //csv file code     private class CSVFile {         InputStream inputStream;          public CSVFile(InputStream inputStream) {             this.inputStream = inputStream;         }          public List<String> read() {              List<String> resultList = new ArrayList<String>();             BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));             try {                 String line;                 while ((line = reader.readLine()) != null) {                     String[] row = line.split(",");                     resultList.add(row[1]);                 }             } catch (IOException e) {                 Log.e("Main", e.getMessage());             } finally {                 try {                     inputStream.close();                 } catch (IOException e) {                     Log.e("Main", e.getMessage());                 }             }             return resultList;         }     } } 

ERROR LOG UPDATE:

java.lang.RuntimeException: Unable to start activity ComponentInfo{com.app.supermarketaislefinder/com.app.supermarketaislefinder.create}: java.lang.NullPointerException     at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2092)     at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2117)     at android.app.ActivityThread.access$700(ActivityThread.java:134)     at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1218)     at android.os.Handler.dispatchMessage(Handler.java:99)     at android.os.Looper.loop(Looper.java:137)     at android.app.ActivityThread.main(ActivityThread.java:4867)     at java.lang.reflect.Method.invokeNative(Native Method)     at java.lang.reflect.Method.invoke(Method.java:511)     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1007)     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:774)     at dalvik.system.NativeStart.main(Native Method)  Caused by: java.lang.NullPointerException     at com.app.supermarketaislefinder.create.onCreate(create.java:232)     at android.app.Activity.performCreate(Activity.java:5047)     at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1094)     at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2056)     at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2117)      at android.app.ActivityThread.access$700(ActivityThread.java:134)      at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1218)      at android.os.Handler.dispatchMessage(Handler.java:99)      at android.os.Looper.loop(Looper.java:137)      at android.app.ActivityThread.main(ActivityThread.java:4867)      at java.lang.reflect.Method.invokeNative(Native Method) 

8 Answers

Answers 1

In the first activity, put your dropdown selected value into bundle before start another activity(intent)

Intent i= new Intent(this, YourSecondClass.class); //Create the bundle Bundle bundle = new Bundle();  //Add your data to bundle bundle.putString("dropdown", dropdown_value);  //Add the bundle to the intent i.putExtras(bundle); startActivity(i); 

In the new(second) activity, get your dropdown value from bundle.

Bundle bundle = getIntent().getExtras();  //Extract the data… String dropdown_value= bundle.getString("dropdown"); 

Answers 2

public class create extends AppCompatActivity {

private LinearLayout mLinearLayout; private ArrayList<SearchableSpinner> mSpinners; //TODO add the below list of buttons and checkboxes // private List<AppCompatButton> mButtons = new ArrayList<>(); private List<CheckBox> mCheckboxes = new ArrayList<>(); private List<View> mViews = new ArrayList<>(); Button buttonGo; Spinner spinner; ...... floatingActionButton.setOnClickListener(new View.OnClickListener() {         @Override         public void onClick(View view) {             Toast.makeText(getBaseContext(), "Item added!", Toast.LENGTH_SHORT).show();              RelativeLayout.LayoutParams params1 = new RelativeLayout.LayoutParams(WindowManager.LayoutParams.WRAP_CONTENT, WindowManager.LayoutParams.WRAP_CONTENT);             RelativeLayout.LayoutParams params2 = new RelativeLayout.LayoutParams(WindowManager.LayoutParams.WRAP_CONTENT, WindowManager.LayoutParams.WRAP_CONTENT);             // Handle the click.               // Handle ze click.             //final Spinner spinner = makeSpinner();             //mLinearLayout.addView(spinner);              spinner = makeSpinner(); } 

Answers 3

I think what you want to do is pass the user selected items from the create screen to the view screen.

You can use a global class to store the values of the selected items. And use it like a normal java class.

public class GlobalClass extends Application {     ArrayList<String> items = new ArrayList<>();      public ArrayList<String> getItems() {         return items;     }      public void setItems(ArrayList<String> items) {         this.items = items;     } } 

Define this in the application tag of the manifest file

<application     android:name=".GlobalClass" 

and use it like this in the onCreate function of both activities

globalClass = (GlobalClass) this.getApplicationContext(); 

then you can use getters and setters to access your selected item list. in create activity,

ArrayList<String> items = new ArrayList<>(); items.add(item); // add you selected item globalClass.setItems(items); 

in view activity,

ArrayList<String> items = globalClass.getItems(); 

Answers 4

buttonGo.setOnClickListener(new View.OnClickListener() {              public void onClick(View v) { if(spinner!=null){  Intent i= new Intent(create.this, viewscreen.class); //Create the bundle Bundle bundle = new Bundle();  //Add your data to bundle bundle.putString("dropdown", dropdown_value);  //Add the bundle to the intent i.putExtras(bundle); startActivity(i);              }          }); 

Answers 5

I don't know why you are stuck in this problem still. When you know to pass values in Activities. If I think about your problem, I get various solutions in my mind.

Solution 1: Use @Angus solution, I checked your code when you followed his answer.

Basically you have to pass an value to next activity, like position/ spinner selected value.

bundle.putString("selectedPos", spinner.getSelectedItemPosition()); 

or

bundle.putString("selectedItem", ((String) spinner.getSelectedItem())); 

Solution 2: You have SharedPreference to store these values in first activity, then get saved values in second activity.

Solution 3: I don't suggest to use Application class to store variables, but yes!, that's a solution. Like this answer. I don't use Application class to store values, because we need to clear the fields after use manually, to recover RAM uses.

Solution 4: As you said both of your Activities are almost same, then why don't you just use one Activity and manage Views accordingly.

Edit

If I am getting right, then you can pass the generated Spinners items list and selected items to next Activity. You can pass Parcelable List for ease.

First Activity passes the Spinner model list.

ArrayList<ModelSpinner> list = new ArrayList<>(); list.add(new ModelSpinner(itemsList, (String) spinner.getSelectedItem())); startActivity(new Intent(this, MainActivity.class).putParcelableArrayListExtra("key", list)); 

Second activity gets the list and make according views

ArrayList<ModelSpinner> list = getIntent().getParcelableArrayListExtra("key"); for (ModelSpinner spinner : list) { //            render spinners     Spinner spinner = makeSpinner(spinner.getItems(),spinner.getSelectedValue());     // todo create method makeSpinner(List<String> list, String selectedItem), add this spinner to your activity. } 

ModelSpinner.class

public class ModelSpinner implements Parcelable {     private ArrayList<String> items;     private String selectedValue;      // getter setter       @Override     public int describeContents() {         return 0;     }      @Override     public void writeToParcel(Parcel dest, int flags) {         dest.writeStringList(this.items);         dest.writeString(this.selectedValue);     }      public ModelSpinner() {     }      protected ModelSpinner(Parcel in) {         this.items = in.createStringArrayList();         this.selectedValue = in.readString();     }      public static final Parcelable.Creator<ModelSpinner> CREATOR = new Parcelable.Creator<ModelSpinner>() {         @Override         public ModelSpinner createFromParcel(Parcel source) {             return new ModelSpinner(source);         }          @Override         public ModelSpinner[] newArray(int size) {             return new ModelSpinner[size];         }     }; } 

Answers 6

The best solution for this scenario will be using ViewModel and LiveData from architectural components library which will simply provide you consistency in data in both the Activities. A single ViewModel for both Activities and shared LiveDatas for both Activities which will be helpful when you update any LiveData from any Activity it will get reflected in all the Activities which is observing the defined LiveData in the ViewModel.

Answers 7

You are calling the context as "This" but is calling it from within a method that overwrites a method in the interface, but the method is not in this class and therefore does not know what "This" is, to solve it do this, in you Create Class:

public class Create extends AppCompatActivity {   private Context context;   @Override     protected void onCreate(Bundle savedInstanceState) {         super.onCreate(savedInstanceState);         setContentView(R.layout.activity_view);         getSupportActionBar().setDisplayHomeAsUpEnabled(true);         context = this;         buttonGo.setOnClickListener(new View.OnClickListener() {                                         public void onClick(View v) {                                              if(spinner!=null){                                                  Intent i= new Intent(context, View.class);                                                 startActivity(i);                                             }                                         };   } } 

You can pass data with the intent,or can pass data using a static variable in the Create class.

Create Class:

    public class Create extends AppCompatActivity {         public static String optionSelected; //other code....             spinner.setOnItemClickListener(new AdapterView.OnItemClickListener() {                         @Override                         public void onItemClick(AdapterView<?> parent, View view, int position, long id) {                           Create.optionSelected = parent.getItemAtPosition(position).toString();                           }                     }); //other code....              } 

In your View Class to call optionSelected:

public class View extends AppCompatActivity {   String dropdown_value= Create.optionSelected;    // rest of code } 

Answers 8

I had a similar requirement. I solved it with a different logic.

  1. Create a class for reference.
  2. Store data in this class, then stringify using Gson and pass it to second activity.
  3. Get back from stringified json to class object using Gson.
  4. OnCreate, update the UI according to the object content u received in Step 3.

This will make the flow in control and development friendly. Hope this serves your requirement well.

Storing the view and transferring is not a better idea since this can lead to development complexity later.

Incase of multiple data for n number of spinners, you can use ArrayList of product objects and create spinner view dynamically.

Read More